├── .gitignore ├── .nojekyll ├── LICENSE.txt ├── Readme.md ├── convert.js ├── docs ├── Manual.md ├── Programming.md └── Trees.md ├── examples ├── bencode.k ├── binpack.k ├── circle.k ├── donut.k ├── hangman.k ├── idioms.k ├── islands.k ├── key.k ├── lexicographic.k ├── merge.k ├── parsing.k ├── runlength.k ├── strings.k ├── tictac.k └── treedepth.k ├── icon.png ├── ike ├── Readme.md ├── audio.js ├── examples │ ├── ajax.k │ ├── asteroids.k │ ├── bounce.k │ ├── brownian.k │ ├── checker.k │ ├── cursor.k │ ├── dissolve.k │ ├── distance.k │ ├── economy.k │ ├── eyes.k │ ├── hexagons.k │ ├── hyperplane.k │ ├── ikeanoid.k │ ├── instrument.k │ ├── islands.k │ ├── life.k │ ├── lindenmayer.k │ ├── lorenz.k │ ├── mandelbrot.k │ ├── musicplayer.k │ ├── paint.k │ ├── palette.k │ ├── plasma.k │ ├── poisson.k │ ├── raster.k │ ├── sierpinski.k │ ├── small.k │ ├── snake.k │ ├── spin.k │ ├── terminal.k │ ├── tiles.k │ ├── triangles.k │ ├── unknown.k │ ├── upc.k │ ├── vector.k │ ├── voronoi.k │ └── voters.k ├── filesaver.js ├── ike.html ├── img │ ├── close.png │ ├── font.png │ ├── full.png │ ├── gist.png │ ├── livecoding.gif │ ├── play.png │ ├── record.png │ ├── stop.png │ ├── swatches.png │ └── tick.png ├── noise.js ├── recording.js └── text.js ├── index.html ├── mobile.html ├── mobile.png ├── oK.js ├── package.json ├── repl.js └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/.nojekyll -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015, John Earnest 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | oK 2 | == 3 | 4 | oK is a toy interpreter for a dialect of the [K programming language](http://en.wikipedia.org/wiki/K_(programming_language)) which aims to be an implementation of [K5](http://kparc.com), the still-evolving bleeding edge version of the language. Expect oK to be buggy, incomplete and occasionally flat-out wrong, but slowly improving over time. Read the [oK Manual](https://github.com/JohnEarnest/ok/blob/gh-pages/docs/Manual.md) for an overview of oK's operators and syntax. 5 | 6 | If you are interested in learning more about K, consider downloading the free version of [kdb](http://kx.com/software-download.php) from Kx Systems, the fine makers of K. Alternatively, [Kona](https://github.com/kevinlawler/kona) is an open-source reimplementation of K3/K4. 7 | 8 | oK does not intend to be particularly fast or suitable for any practical purpose beyond learning, instead emphasizing simplicity of implementation. JavaScript was chosen as an implementation language because it is familar to many programmers and has first-class functions. 9 | 10 | Trying oK 11 | --------- 12 | The easiest way to run oK is using the [Browser-based REPL](http://johnearnest.github.io/ok/index.html). This REPL features a few special commands which can be issued at the beginning of a line: 13 | 14 | - `\\` (while entering a multiline expression) cancel this expression. 15 | - `\e` toggle the scratchpad editor pane. This editor's content is persisted via localstorage (in case your browser crashes or is closed accidentally). 16 | - `\r` run the contents of the editor pane. Alternately, press shift+enter with the editor focused. 17 | - `\c` clear the output log. 18 | - `\t` time executing the remainder of the line. 19 | - `\f` list all presently defined functions. 20 | - `\v` list all presently defined variables. 21 | - `\u` generates a code url from the remainder of the line, as described below. 22 | 23 | oK provides several numbered IO verbs: 24 | 25 | - dyadic `0:` takes a symbol or string as its left argument and writes the right argument to that destination as text. The right argument can be a symbol, a string, or a list of symbols or strings. In the browser-based REPL the symbol is ignored and output is always sent to the console. In the command-line REPL output is sent to a file as specified by the left argument, or to `stdout` if the left argument is empty. 26 | - monadic `0:` reads the content of a file or a URL. In the browser-based REPL it takes a string as its right argument and performs a synchronous HTTP request to that URL. The result will be a tuple containing the HTTP status code followed by the response, if any. You can use this in conjunction with pastebins to load code from elsewhere or access RESTful web APIs. Note that most web browsers restrict cross-site HTTP requests from javascript under the [same-origin policy](http://en.wikipedia.org/wiki/Same-origin_policy)- you'll need a server which responds with an Access-Control-Allow-Origin header. GitHub gists will do: 27 | 28 | url: "https://gist.githubusercontent.com/anonymous/cc0ef05c00940044eb0a/raw/" 29 | "https://gist.githubusercontent.com/anonymous/cc0ef05c00940044eb0a/raw/" 30 | 0:url 31 | (200 32 | "/ generate a times table\nt*/:t:!10\n") 33 | .*|0:url 34 | (0 0 0 0 0 0 0 0 0 0 35 | 0 1 2 3 4 5 6 7 8 9 36 | 0 2 4 6 8 10 12 14 16 18 37 | 0 3 6 9 12 15 18 21 24 27 38 | 0 4 8 12 16 20 24 28 32 36 39 | 0 5 10 15 20 25 30 35 40 45 40 | 0 6 12 18 24 30 36 42 48 54 41 | 0 7 14 21 28 35 42 49 56 63 42 | 0 8 16 24 32 40 48 56 64 72 43 | 0 9 18 27 36 45 54 63 72 81) 44 | In the command-line REPL `0:` reads a file as text. The right argument can be a symbol or a string specifying the file path. If the path is to a directory, `0:` returns its listing. If the path is empty and oK is not running interactively, `0:` tries to read text from `stdin` until it encounters a `'\n'`. 45 | 46 | - monadic `1:` works just like monadic 0: except it expects the response to be JSON rather than arbitrary text, and it attempts to parse it into a K data structure you can then manipulate: 47 | 48 | url:"http://api.openweathermap.org/data/2.5/weather?q=London,uk" 49 | "http://api.openweathermap.org/data/2.5/weather?q=London,uk" 50 | t:1:url 51 | (200;[coord:[lon:-0.13;lat:51.51];sys:[type:1;id:5091;message:0.0224;country:"GB";sunrise:1425709902;sunset:1425750674];weather:,[id:800;main:"Clear";description:"Sky is Clear";icon:"01d"];base:"cmc stations";main:[temp:288.11;pressure:1024;humidity:44;temp_min:286.85;temp_max:289.82];wind:[speed:6.2;deg:230];clouds:[all:0];dt:1425736003;id:2643743;name:"London";cod:200]) 52 | t[1;`weather;0;`description] 53 | "Sky is Clear" 54 | 55 | - monadic `5:` returns a printable string representation of the right argument, as in K3. Sometimes this can be useful for debugging: 56 | 57 | 5: 1 2 3 58 | "1 2 3" 59 | 5:"foo" 60 | "\"foo\"" 61 | 5: {x+2*y} 62 | "{[x;y]x+2*y}" 63 | 64 | If you visit the page with a `?run=` URL parameter, the remainder of the URL will be URI decoded and executed. The `\u` command can create a link for you based on an expression. You can combine this feature with monadic `0:` to run larger programs: 65 | 66 | \u 1+2 67 | oK code url: 68 | http://johnearnest.github.io/ok/index.html?run=%201%2B2 69 | 70 | \u .*|0:"https://gist.githubusercontent.com/anonymous/cc0ef05c00940044eb0a/raw/" 71 | oK code url: 72 | http://johnearnest.github.io/ok/index.html?run=%20.*%7C0%3A%22https%3A%2F%2Fgist.githubusercontent.com%2Fanonymous%2Fcc0ef05c00940044eb0a%2Fraw%2F%22 73 | 74 | Command Line Mode 75 | ----------------- 76 | Alternatively, you can run oK via the command line with [Node.js](http://nodejs.org). `test.js` runs a series of automated tests: 77 | 78 | je@indigo$ node test.js 79 | 80 | You can also try out oK from the included REPL. Note that at the time of writing, the release version of Node.js does not portably support blocking reads from stdin- the REPL has been tested with Node v0.11.14 on OSX. 81 | 82 | je@indigo$ node repl.js 83 | oK v0.1 84 | 85 | +/4 5 6 86 | 15 87 | 88 | 1 2 3+2 5 89 | length error. 90 | 91 | a:"some text" 92 | "some text" 93 | 94 | "t"=a 95 | 0 0 0 0 0 1 0 0 1 96 | 97 | This REPL is very simplistic compared to the CLI provided in a complete K interpreter and lacks interactive debugging facilities. When you're done, type `\\` or press Ctrl+D to exit. If you supply a filename as an argument to the REPL, it will instead execute that file: 98 | 99 | je@indigo$ node repl.js examples/hangman.k 100 | _____ > p 101 | _pp__ > e 102 | _pp_e > a 103 | app_e > l 104 | apple 105 | 106 | Mobile 107 | ------ 108 | On mobile devices like cell phones, try [oK Mobile](http://johnearnest.github.io/ok/mobile.html)! 109 | 110 | ![Mobile View Screenshot](https://raw.githubusercontent.com/JohnEarnest/ok/gh-pages/mobile.png) 111 | 112 | Tilting your device horizontally will provide a QWERTY touch-keyboard, and a vertical orientation will provide a calculator-like keypad which provides access to all K verbs and adverbs with a single keypress. Tapping on items from the output history copies them to your edit buffer. 113 | 114 | oK mobile provides graphing functionality in the form of the built-in `pl` (plot line) and `ps` (plot scatter) functions. Both will automatically rescale to suit the data you provide. The first argument to each function specifies the domain (x axis) and can be a list of numbers or a single number n (interpreted as `!n`). The second argument specifies the range (y axis) and can be a list of numbers or a monadic function f (interpreted as `f'x`). 115 | 116 | oK mobile supports the `0:` verb for reading from (monadically) or writing to (dyadically) browser-local storage. If the left argument is an empty symbol, output will be printed to the console, as with most K interpreters. Symbols and strings are interchangeable as `0:` sources/destinations. Monadic `5:` produces a printable string representation of its right argument. 117 | 118 | The dyadic `6:` verb permits creating custom user menus. The left argument must be a string, which will be used as a title for the menu. The right argument may be either a list or a dictionary of monadic/niladic functions. If the right argument is a list, the menu will contain a button for each list item, and clicking the button will append that button's contents to the edit line. If the right argument is a dictionary, buttons will be created for each key and clicking the button will execute the associated monad/nilad. If the nilad returns a string, it will be appended to the edit line. Consider a few examples: 119 | 120 | "simple" 6: ("foo";`bar;`baz); 121 | "my menu" 6: `a`b!({`0:"pressed A";0};{`0:"pressed ",x;0}); 122 | "another" 6: `a`b!({`0:"pressed A";0};{"append this"}); 123 | 124 | The dyadic `1:` verb permits asynchronously loading the contents of a document as a string via an HTTP GET. The right argument must be a URL as a string. If the left argument is a symbol, the result of the call will be stashed in a variable with the corresponding name when the result comes in. If the left argument is a monad, it will be evaluated as a callback with the result when it comes in. 125 | 126 | The dyadic `2:` verb permits asynchronously storing a string via an HTTP POST. The left argument must be a URL as a string. The right argument should be the value to write as a string. 127 | 128 | These mechanisms makes it possible to load or store serialized environments or boot scripts from external storage. Browser security constraints require that the remote server provide a `Access-Control-Allow-Origin` header, which is unfortunately not the case with most pastebin services. GitHub [gists](https://gist.github.com) will work (read-only), or you could run [this server](https://gist.github.com/JohnEarnest/34b027c62eaf3c768b8963a4daa70457) on a local machine (read and write, if enabled). 129 | 130 | Assuming you started up the above server on a LAN with a machine with the local IP address `192.168.0.10`, you could fetch the contents of a file in that server's directory given by the `BASE_DIR` variable named `foo.txt` into a variable named `v` like so: 131 | 132 | u: "http://192.168.0.10:10101/foo.txt" 133 | `v 1: u 134 | 135 | And you could then overwrite this file with new data via `2:` 136 | 137 | u 2: "Replacement Data." 138 | 139 | If you store a K string in a local storage variable named `boot`, it will be executed when oK mobile starts up. Similarly, if you store a dictionary in a local storage variable named `env` it will replace the default environment at startup. Either of these mechanisms may be used to stash your favorite utility functions or frequently used data. Recall that `.{}` can be used at the base level to retrieve a reference to the root environment, so `"env" 0: .{}` is one way to back up your entire workspace. Setting either `boot` or `env` to the empty list `()` will stub it out and prevent it from being used at startup. 140 | 141 | Finally, oK mobile supports a basic set of backslash commands: 142 | 143 | - `\c` clear the output log. 144 | - `\t` time executing the remainder of the line. 145 | - `\x` list all presently defined functions. 146 | - `\y` list all presently defined variables. 147 | 148 | How Does It Work? 149 | ----------------- 150 | oK's interpreter centers around trees of objects (called k-values) which represent K datatypes. Every k-value has a field `t` which indicates the object type and a `v` field containing JavaScript value(s) such as arrays or numbers. Some k-values do not correspond to K types but instead represent nodes of an abstract syntax tree (AST) comprising a program, and may contain additional fields. 151 | 152 | The section titled _Primitive Verbs_ contains implementations of the wide range of primitive operators in K which operate on and return k-values. In these implementations the overloaded variations of K primitives which operate on different datatypes have often been split into several distinct functions. 153 | 154 | The section titled _Primitive Adverbs_ is similar, providing implementations of K adverbs which manipulate k-values. One way that oK deviates from other K interpreters is that it does not internally discriminate between lists and unitype vectors, which forces adverbs to perform dynamic dispatch of the verb they apply every time they iterate. This simplifies the implementation but comes with substantial overhead. 155 | 156 | The _Interpreter_ provides a verb dispatch table (organized between monadic/dyadic forms and variations between verb forms applied to combinations of list and non-list (atomic) datatypes) and mechanisms for walking k-value trees to evaluate expressions. The functions `am`, `ad`, `ar` and `al` generalize the process of "conforming" datatypes to feed into primitive functions. This section also contains the functions which implement the `.`, `@` and `amend`/`dmend` primitives as they are more tightly connected to and used by the interpreter than most others. This section also contains a class called Environment which represents a linked-dictionary structure used for variable lookup and scope management. To execute a k-value tree, use the `run()` function and provide a reference to a global Environment to reference. 157 | 158 | The _Tokenizer_ uses regular expressions to identify and consume lexical tokens from K source text. Presently the tokenizer maintains some global state so that it is not necessary to thread tokenizer state throughout the parser. 159 | 160 | The _Parser_ uses an ad-hoc left-to-right recursive-descent approach. This gets a bit hairy and is likely to change substantially over time. As it breaks a program into tokens and assembles a k-value AST, it also desugars some special syntactic forms to avoid complexity in the interpreter. For example, a compound assignment of the form 161 | 162 | t[x]+:y 163 | 164 | Is rewritten into an application of the form `dmend`: 165 | 166 | ..[`t;x;+:;y] 167 | 168 | To convert a JavaScript string into a k-value tree, use the `parse()` function. 169 | 170 | The _Prettyprinter_ reverses the work of the Parser, turning a k-value back into a human-comprehensible, properly indented form. oK's prettyprinter output of a function or verb chain represents the desugared form of expressions and thus during debugging can help clarify whether a problem occurs at the parser or interpreter level. Formatting is very similar to that used by other K interpreters but may differ in small ways, generally erring on the side of longer, more explicit output. Invoke the prettyprinter by using the `format()` function on a k-value or JavaScript array of k-values. 171 | -------------------------------------------------------------------------------- /convert.js: -------------------------------------------------------------------------------- 1 | //////////////////////////////////// 2 | // 3 | // A companion to oK which bridges 4 | // the gap between k-values and 5 | // native JavaScript types. 6 | // 7 | // John Earnest 8 | // 9 | //////////////////////////////////// 10 | 11 | "use strict"; 12 | 13 | function tok(v) { 14 | if (v == null) { return { t:11, v:null }; } 15 | if (typeof v == 'number') { return { t:0, v:v }; } 16 | if (typeof v == 'string') { 17 | var r = []; 18 | for(var z=0;z':v 239 | 0 1 0 0 0 0 0 1 0 0 0 1 240 | 241 | If you need more context, you can split the list appropriately yourself. To provide sliding windows into a list `x` which each have a length `y`: 242 | 243 | {x(!y)+/:!(#x)-y-1}[4 8 9 10 22 3;3] 244 | (4 8 9 245 | 8 9 10 246 | 9 10 22 247 | 10 22 3) 248 | 249 | K6 introduces `window` (`'`), which makes this much simpler: 250 | 251 | 3'4 8 9 10 22 3 252 | (4 8 9 253 | 8 9 10 254 | 9 10 22 255 | 10 22 3) 256 | 257 | If you don't want these windows to overlap, `reshape` with a "greedy" `0N` is the ticket: 258 | 259 | 0N 3#4 8 9 10 22 3 7 0 9 260 | (4 8 9 261 | 10 22 3 262 | 7 0 9) 263 | 264 | 0N 2#4 8 9 10 22 3 7 0 265 | (4 8 266 | 9 10 267 | 22 3 268 | 7 0) 269 | 270 | If the iterations are truly sequentially dependent, use dyadic `over`. Consider processing a list of typed characters where each "#" represents a backspace. You can't simply remove every character followed by a "#", as several "#"es may appear consecutively, as in "ab#def##". If we treat the left argument to our dyadic reducing function as a stack we can push elements into with `x,y` and pop elements from with `-1_x`, we can arrive at the following solution: 271 | 272 | (){$[y="#";-1_x;x,y]}/"ab#def##" 273 | "ad" 274 | 275 | (Or a slightly shorter equivalent, if we're golfing:) 276 | 277 | (){(x,y;-1_x)y=35}/"ab#def##" 278 | 279 | The way this works is clearer if we show the intermediate results: 280 | 281 | {x{x,"|",y}'(){$[y="#";-1_x;x,y]}\x}"ab#def##" 282 | ("a|a" 283 | "b|ab" 284 | "#|a" 285 | "d|ad" 286 | "e|ade" 287 | "f|adef" 288 | "#|ade" 289 | "#|ad") 290 | 291 | Scan `\` combined with `|` or `&` and applied to a boolean list produces vectors which identify the suffix or prefix, respectively, for which a property holds. Sometimes these are called *smear vectors*: 292 | 293 | |\0 0 1 0 1 1 0 294 | 0 0 1 1 1 1 1 295 | 296 | &\1 1 1 0 1 1 0 297 | 1 1 1 0 0 0 0 298 | 299 | Consider how we can use this type of composition to write a function which trims leading spaces from a string: 300 | 301 | {~" "=x}" some text" 302 | 0 0 1 1 1 1 0 1 1 1 1 303 | 304 | {x@&~" "=x}" some text" 305 | "sometext" 306 | 307 | {|\~" "=x}" some text" 308 | 0 0 1 1 1 1 1 1 1 1 1 309 | 310 | {x@&|\~" "=x}" some text" 311 | "some text" 312 | 313 | If you find yourself seemingly needing to update several data structures on each iteration of an algorithm, consider whether you can break the algorithm into several simpler passes. For example, consider a program which, given a graph as an adjacency list `g`, finds the visited items at each layer of a breadth-first traversal. We can first simply walk the graph by expanding a visited set, and then afterwards extract each ply's expansion by using *set difference*: 314 | 315 | g: (1 2 4;0 5;0 6 7;,7;0 9;1 8;,2;2 3 9;5 9;4 7 8); 316 | 317 | {?x,,/g@x}\,0 318 | (,0 319 | 0 1 2 4 320 | 0 1 2 4 5 6 7 9 321 | 0 1 2 4 5 6 7 9 8 3) 322 | 323 | ^':{?x,,/g@x}\,0 324 | (,0 325 | 1 2 4 326 | 5 6 7 9 327 | 8 3) 328 | 329 | As another example, consider gathering a vector representing the shape of a nested rectangular structure. As a first pass, we can progressively strip the structure apart, one layer at a time. Then, measure the size of each item: 330 | 331 | *:\((1 2 3;4 5 6);(7 8 9;10 11 12)) 332 | (((1 2 3 333 | 4 5 6) 334 | (7 8 9 335 | 10 11 12)) 336 | (1 2 3 337 | 4 5 6) 338 | 1 2 3 339 | 1) 340 | 341 | #:'*:\((1 2 3;4 5 6);(7 8 9;10 11 12)) 342 | 2 2 3 1 343 | 344 | -1_#:'*:\((1 2 3;4 5 6);(7 8 9;10 11 12)) 345 | 2 2 3 346 | 347 | Making The Grade 348 | ---------------- 349 | The `grade up` (`<`) and `grade down` (`>`) operators have one extremely obvious application: sorting a list, in combination with `@`: 350 | 351 | {x@0}{*&+/'tree=x}\4 102 | 0 2 4 103 | 104 | For each of these nodes we simply need to determine whether the child we're interested in was the left or right. More generally, we want the index in their successor list where the next node can be found: 105 | 106 | p:{*&+/tree=x}'1_|{x>0}{*&+/'tree=x}\ 107 | p'1_!#tree 108 | (,0 109 | ,1 110 | 0 0 111 | 1 0 112 | 1 1 113 | 1 1 1) 114 | 115 | Going the other way, if we have just one such path we can easily obtain the node at that position via over: 116 | 117 | 0{tree[x;y]}/1 0 118 | 4 119 | 120 | Note that these approaches generalize to N-ary trees and permit treating any node of a tree as a starting point, rather than just node 0. 121 | 122 | Build a Complete Binary Tree 123 | ---------------------------- 124 | A complete binary tree of size N contains N nodes. If we list complete tree matrices a clear pattern emerges: 125 | 126 | 1 -> (0 0) 127 | 2 -> (1 0;0 0) 128 | 3 -> (1 2;0 0;0 0) 129 | 4 -> (1 2;3 0;0 0;0 0) 130 | 5 -> (1 2;3 4;0 0;0 0;0 0) 131 | 6 -> (1 2;3 4;5 0;0 0;0 0;0 0) 132 | 133 | We can produce any such tree by generating an appropriate enumeration (`1+!2*x`), forcing all indices which would reference nodes outside this boundary to zero (`a*x>a:`) and then reshaping the result into a list of pairs (`0N 2#`): 134 | 135 | {0N 2#a*x>a:1+!2*x} 9 136 | (1 2 137 | 3 4 138 | 5 6 139 | 7 8 140 | 0 0 141 | 0 0 142 | 0 0 143 | 0 0 144 | 0 0) 145 | 146 | An Alternate Take 147 | ----------------- 148 | The columnar tree representation we've been working with up to this point behaves nicely in many cases. You may have noticed a few downsides, though. There are odd edge cases: we have to treat the zero index specially and appending to and removing from such a representation is enormously clumsy. 149 | 150 | How can we fix this? Turn it on its head! Instead of using links from a parent to each child, have each node track the index of its parent. The root will be indicated with a node which links to itself. A side benefit to this representation is that trees require only a single flat _shape vector_ no matter how many children may be attached to any given node; N-ary trees are not a special case. 151 | 152 | a 153 | / \ 154 | b c 155 | /| / \ 156 | d e f g 157 | /|\ 158 | h i j 159 | / 160 | k 161 | 162 | d:`a`b`c`d`e`f`g`h`i`j`k 163 | t: 0 0 0 1 1 2 2 6 6 6 7 164 | 165 | Without delving into too much detail, we can easily enough carry out the same sorts of operations as above: 166 | 167 | |d@(t@)\d?`h / path from root 168 | `a`c`g`h 169 | 170 | d@{&0||/t=/:x}\,d?`c / reachable successors (BFS) 171 | (,`c 172 | `f`g 173 | `h`i`j 174 | ,`k 175 | ()) 176 | 177 | *d@&t=!#t / identify the root 178 | `a 179 | 180 | d@&^t?!#t / identify leaf nodes 181 | `d`e`f`i`j`k 182 | 183 | Note that the vector representing a given tree is not unique. Consider the following equivalent representations of the same tree: 184 | 185 | a 186 | / \ 187 | b d 188 | \ 189 | c 190 | 191 | ud:`c`a`b`d 192 | ut: 2 1 1 1 193 | 194 | nd:`a`b`c`d 195 | nt: 0 0 1 0 196 | 197 | We'll say a _normalized tree_ is one in which parent nodes strictly precede their children. Trees glued together using our append procedure will preserve this property, and our remove procedure depends on it. Checking whether a tree is normalized is fairly straightforward- no parent index should be greater than the index of the current node: 198 | 199 | norm: {~|/(!#x)t:z-*y;0; y[1]+x@t]}; 7 | p: {[c;i] (&1+c){a[x;i@y]'!#x}\!#i}; 8 | 9 | p[5;(2 12;1 10;3 20;2 15)] 10 | -------------------------------------------------------------------------------- /examples/circle.k: -------------------------------------------------------------------------------- 1 | 2 | / draw a circle 3 | 4 | `0:"\n"/,/'(" ";"oo")@c'(c:{x,|x})t{11>%(x*x)+(y*y)}/:t:|!13; 5 | -------------------------------------------------------------------------------- /examples/donut.k: -------------------------------------------------------------------------------- 1 | 2 | / render an ANSI-art rotating torus 3 | / an adaptation of https://www.a1k0n.net/2011/07/20/donut-math.html 4 | / which just renders the Z-buffer directly and uses a lower point density. 5 | 6 | rotate: { cx:2.3+cos y 0; cy: sin y 0 / [(A;B);(theta;phi)] 7 | cp: cos y 1; sp: sin y 1 8 | ca: cos x 0; sa: sin x 0 9 | cb: cos x 1; sb: sin x 1 10 | xp: (cx*((cb*cp)+(sa*sb*sp)))-cy*ca*sb 11 | yp: (cx*((sb*cp)-(sa*cb*sp)))+cy*ca*cb 12 | zp: 1%5+(ca*cx*sp)+cy*sa 13 | (_40-30*xp*zp;_20-20*yp*zp;zp) } 14 | 15 | render: {(40 80#0){.[x;|2#y;|;y 2]}/+rotate[x;grid]} 16 | grid: .8*!2#80 17 | disp: `0:0x1B5B48,"\n"/" .,-~:;=!*#$@"@_15* 18 | main: {1}{disp render x; .07 .03+x}/0 0 19 | -------------------------------------------------------------------------------- /examples/hangman.k: -------------------------------------------------------------------------------- 1 | 2 | / An interactive text-based game of Hangman 3 | 4 | w: *1?("aardvark";"apple";"peanut";"etc") / pick a word 5 | c: {|/w=/:x} / correctly guessed 6 | b: {("_",'w)@'c x} / word with blanks 7 | p: {`0:" > ";*0:`} / prompt for a letter 8 | {~&/c x}{`0:b x; x,p[]}/"__"; `0:w,"\n"; 9 | -------------------------------------------------------------------------------- /examples/idioms.k: -------------------------------------------------------------------------------- 1 | 2 | / K idioms. 3 | / derived from http://www.softwarepreservation.org/projects/apl/Papers/THEAPLIDIOMLIST 4 | / many idioms described already have K primitives or simple juxtapositions. 5 | / these are a few which caught my eye as non-obvious and useful and translate nicely to K. 6 | 7 | ( 8 | 9 | {x>\:!|/x}[0 2 3 7 5 1] / (5.3) histogram 10 | {x@&|\~" "=x} " some whitespace " / (5.5a) strip leading spaces 11 | {x@&||\~" "=|x}" some whitespace " / (5.5b) strip trailing spaces 12 | {x@&a|1_1!1,a:~" "=x}" a b c d " / (5.5c) compress repeated spaces 13 | {&//x=+x}(1 2 3;2 3 2;3 2 1) / (6.6) is x a symmetric matrix? 14 | |\0 1 1 0 1 0 0 / (7.5) right smear 15 | +/&\1 1 1 0 1 0 0 1 0 / (14.1) index of leftmost 0 16 | 17 | ) 18 | -------------------------------------------------------------------------------- /examples/islands.k: -------------------------------------------------------------------------------- 1 | 2 | / Given a boolean matrix, identify regions which are orthogonally connected. 3 | / adapted from https://github.com/kevinlawler/kona/wiki/Islands for K5. 4 | / K5 lacks a 'shape' primitive, so we must use # and #* to get the same effect. 5 | / similarly, we must define our own 'rotate' as k5 omits this primitive. 6 | 7 | col: {x*s#1+!*/s:(#x;#*x)}; / give each 1 a unique id 8 | ab: +0,+0,; / add a border of zeroes 9 | rb: 1_'1_; / remove the border of zeroes 10 | r: {y@(#y)!x+!#y}; / rotate list y by x 11 | adj: {(,x),(-1 1r'\:x),(-1 1)r\:x}; / adjacent cells 12 | mrg: {(~~x)*|/adj x}; / merge neighboring ids 13 | rc: {(?0,,/x)?x}; / renumber ids sequentially 14 | isl: {rc rb(mrg/ab col x)}; / find islands 15 | 16 | / Example: 17 | isl (1 0 0 0 1;1 1 1 0 0;0 0 0 0 1;0 0 0 1 1;1 0 1 1 1;0 0 1 0 1) 18 | -------------------------------------------------------------------------------- /examples/key.k: -------------------------------------------------------------------------------- 1 | 2 | / The following is a K translation of some core ideas from 3 | / "The Key to a Data Parallel Compiler" (Aaron Hsu, 2016) 4 | / http://dl.acm.org/citation.cfm?id=2935331 5 | 6 | / A node coordinate matrix is an expanded form of a depth-vector 7 | / tree representation which gives nodes lexicographically sorted 8 | / coordinate vectors corresponding to a depth-first traversal. 9 | / Parent coordinates are prefixes of their children, so a variety 10 | / of structural queries can be performed in parallel. 11 | 12 | / constructing the node coordinate matrix: 13 | 14 | t: {y*x>!#y} / x take y with right zero pad 15 | c: {(1+x)t'+\x=/:\:!1+|/x} / node coordinate matrix 16 | p: {&/x{(~y)|x=y}'y} / y is a prefix of x 17 | a: {f@{|/x*!#x}'(x t'y)p/:\:f:y@&z} / ancestors (depth;ncm;mask) 18 | k: {x'y@=z} / key (reducer;values;groups) 19 | 20 | / examples of using 'key': 21 | / note that in K, it is natural for key to produce a dict, 22 | / rather than a pair of key-value columns in a matrix. 23 | 24 | k[+/;1 2 5;`x`z`z] / [x:1;z:7] 25 | k[#:;v;v: 1 1 4 0 1 3 1] / 1 4 0 3!4 1 1 1 26 | 27 | / using node coordinates to expand 28 | / AST queries given (depth;type;val;mask) 29 | e:{[x;y;z;m] (1_+(x;y;z;i))@=1_a[x;i:c x;m]} 30 | 31 | Fd: 0 1 2 3 4 4 4 2 3 / depth 32 | Ed: 0 1 2 2 2 1 1 2 2 2 33 | Ft: "FEFEVPVAN" / types 34 | Et: "EEVPVPEVPV" 35 | Fv: "f000w+w07" / values 36 | Ev: "v0a+b%0c*d" 37 | e[Fd;Ft;Fv;Ft="F"] / function lifting 38 | e[Ed;Et;Ev;Et="E"] / expression flattening 39 | -------------------------------------------------------------------------------- /examples/lexicographic.k: -------------------------------------------------------------------------------- 1 | 2 | / Generate lexicographically ordered permutations of a list, 3 | / one permutation at a time. np is a helper definition. 4 | / ap generates all permutations starting from a sorted list. 5 | 6 | np: {{x,|y}.(0,1+*y)_x[y]:x[|y]} / next permutation for (x;pivots) 7 | lp: {a:*|&>':x / non-increasing suffix (pivot+1) 8 | b:{*|&(x@y-1) pivot 9 | np[x,();(a-1;b)]} / swap pivots, reverse suffix 10 | 11 | ap: {(-1+*/1+!#x)lp\x} / there are n! permutations of a list of length n 12 | 13 | / Examples: 14 | ap'("ABC";1 2 3 4;`one`two) 15 | -------------------------------------------------------------------------------- /examples/merge.k: -------------------------------------------------------------------------------- 1 | / recursive merge sort 2 | / merge[] can handle any number of sorted partitions. 3 | 4 | rec: {[p;f;d;c;x]$[p x;f x;c@rec[p;f;d;c]'d x]} 5 | merge: {&/c@'+{y+t=&/t:x@'y}[c:x,\:0w]\[#1_,/x;&#x]} 6 | msort: rec[2>#:;{x};2 0N#;merge] 7 | 8 | msort 1 9 2 3 4 8 0 9 | -------------------------------------------------------------------------------- /examples/parsing.k: -------------------------------------------------------------------------------- 1 | / Parser Combinators, K-style 2 | 3 | / A parser is a monad which accepts a string (s) 4 | / and returns a pair (c;v). If the parser matches 5 | / on the head of s, c will contain the number of characters 6 | / consumed and v contains a result value, which can be anything. 7 | / If the parser fails to match, it will indicate failure 8 | / by reporting c as -1. 9 | 10 | / Parser combinators are meant to be projected with arguments 11 | / to result in a parser. prod[] can be used to post-process 12 | / the result value of successful parses. choose[] and seq[] 13 | / combine parsers to take the first of several options which match 14 | / or require several parsers to match in sequence, respectively. 15 | 16 | / eof[] matches the end of a string/file and returns (). 17 | / anychar[] matches any character and returns it. 18 | / oneof[] matches any character in t and returns it. 19 | / lit[] matches the entire string t and returns it. 20 | / not[] succeeds and consumes 0 characters if a parser fails. 21 | / has[] succeeds and consumes 0 characters if a parser succeeds. 22 | / times[] matches a parser exactly n times. 23 | / star[] matches a parser zero or more times. 24 | / option[] matches a parser zero or one time(s). 25 | / plus[] matches a parser one or more time(s). 26 | / nof[] consumes a prefix which yields a numeric value, 27 | / and then matches a parser g that many times in a row. 28 | 29 | fail: (-1;"") 30 | none: (0;()) 31 | err: 0>*: 32 | starts: {(,/,x)~((#x)&#y)#y} 33 | eof: {[s] $[#s;fail;none]} 34 | anychar: {[s] $[#s;(1;*s);fail]} 35 | oneof: {[t;s] $[(*s) in t;(1;*s);fail]} 36 | lit: {[t;s] $[starts[t;s];(#t;t);fail]} 37 | not: {[g;s] $[err g s;none;fail]} 38 | has: {[g;s] $[err r:g s;fail;(0;r 1)]} 39 | prod: {[g;f;s] $[err r:g s;r;(*r;f@*|r)]} 40 | choose: {[a;s] fail{$[err x;y s;x]}/a} 41 | seq: {[a;s] none{$[err x;x;err r:y(*x)_s;r;(+;{x,,y}).'+(x;r)]}/a} 42 | times: {[n;g;s] n{$[err x;x;err r:g(*x)_s;r;(+;{x,,y}).'+(x;r)]}/none} 43 | star: {[g;s] *1_|{~err x}{$[err r:g(*x)_s;r;(+;{x,,y}).'+(x;r)]}\none} 44 | option: {choose(x;lit "")} 45 | plus: {[g;s]prod[seq(g;star g);{(,x),y}/;s]} 46 | nof: {[a;g;s]$[err n:a s;n;((*n)+*v;*|v:times[*|n;g;(*n)_ s])]} 47 | 48 | / Example: bencode parser 49 | 50 | / Note the use of symbols for self-reference or use-before-definition 51 | / among the parsing rules comprising a complete parser: 52 | 53 | digits: plus oneof "0123456789" 54 | number: prod[seq(option lit "-";digits);.,/] 55 | bstr: nof[prod[seq(digits;lit ":");.*:];anychar] 56 | bint: prod[seq(lit "i";number ;lit "e");{x 1}] 57 | blst: prod[seq(lit "l";plus`atom ;lit "e");{x 1}] 58 | bdict: prod[seq(lit "d";plus seq(bstr;`atom);lit "e");{!/+x 1}] 59 | atom: choose(bdict;bint;blst;bstr) 60 | bencode: prod[seq(atom;eof);*:] 61 | 62 | test: {*|bencode x} 63 | (test "i47e" 64 | test "i-3992e" 65 | test "li10ei20ee" 66 | test "4:spamE" 67 | test "l3:foo3:bare" 68 | test "l3:fooi99e4:barfi88ee" 69 | test "d3:fooi99e4:barfi88ee" 70 | test "i23etrailinggarbage") 71 | -------------------------------------------------------------------------------- /examples/runlength.k: -------------------------------------------------------------------------------- 1 | 2 | / Simple run-length encoder and decoder 3 | 4 | rle: {{(#x;*x)}'(&~=':x)_x} 5 | rld: ,/#/' 6 | 7 | / Examples: 8 | (rle "AAABBCCDAABB" 9 | rld ((5;"A");(3;"C");(1;"B"))) 10 | -------------------------------------------------------------------------------- /examples/strings.k: -------------------------------------------------------------------------------- 1 | 2 | / 20 string algorithm questions 3 | / based on the list at http://javarevisited.blogspot.co.uk 4 | / some are trivial, some demonstrate interesting k5/k6 features. 5 | 6 | ( 7 | 8 | &1<#:'= "applause" / 1. find duplicated characters 9 | ~/{x@#:'= "abdbbac" / 17. most frequently occurring char 25 | ^ ["peeled";"e"] / 18. remove instances of a character 26 | *{x~|x}#t@>#:'t:,/(-1_)\'(1_)\ "issrawar" / 19. longest palindrome substring 27 | {x@<#:'x} ("am";"i";"you";"they") / 20. sort list of strings by length 28 | 29 | ) 30 | -------------------------------------------------------------------------------- /examples/tictac.k: -------------------------------------------------------------------------------- 1 | 2 | / Tic-Tac-Toe for two 3 | 4 | pr: `0:"\n", / print a line to stdout 5 | num: {*(0:`)-"0"} / read a digit from stdin 6 | 7 | lines: (,0 4 8),(,2 4 6),t,(+t:3 3#!9) / diags, rows, cols 8 | won: {|/(&/(y+1)=)'x[lines]} / did player y win board x? 9 | cell: {$[~x;"012345678"@y;".xo"@x]} / format one board cell 10 | disp: {pr@"\n"/"|"/'3 3#cell.'x,'!#x;x} / display the whole board 11 | ask: {pr("ox"@p),"> ";num[]} / prompt for a move 12 | pick: {[a]{~0~a[x]}{x;9!ask[]}/0} / repeat until valid move 13 | move: {x[pick[x]]:1+(p::~p)} / make a move 14 | done: {won[x;p]|~+/0=x} / player won or no moves remain 15 | 16 | end: {pr$[won[x;0];"X Wins!";won[x;1];"O Wins!";"Tie!"]} 17 | p:0; end disp {~done x}{move disp x}/9#0; 18 | -------------------------------------------------------------------------------- /examples/treedepth.k: -------------------------------------------------------------------------------- 1 | 2 | / Given a list of elements assembled 3 | / in order into a binary tree, 4 | / how deep is a given element? 5 | 6 | ranges: {$[(z>y[0])&zx; y[0],z; y]} 7 | depth: {-1+#?(,t),(t:-0w 0w)ranges[x@y]\(y+1)#x} 8 | 9 | / should be: 0 1 2 1 3 2 2 3 10 | depth[5 1 3 9 4 7 0 8]'!8 11 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/icon.png -------------------------------------------------------------------------------- /ike/Readme.md: -------------------------------------------------------------------------------- 1 | iKe 2 | === 3 | iKe is an experimental programming environment built on oK. It allows you to rapidly write event-driven graphical programs in K. Try it [In your browser](http://johnearnest.github.io/ok/ike/ike.html)! 4 | 5 | ![Livecoding Demo](https://raw.githubusercontent.com/JohnEarnest/ok/gh-pages/ike/img/livecoding.gif) 6 | 7 | The interface consists of an editor pane on the left with a status bar and display on the right. Pressing shift+enter in the editor will compile and run the K program. Escape will halt a running program. Pressing shift+enter with a section of text selected will execute just that snippet and display the results, allowing quick experimentation and sanity checking. 8 | 9 | Read about iKe in *Vector*: [A graphical sandbox for K](http://archive.vector.org.uk/art10501610). 10 | 11 | Output 12 | ------ 13 | To draw to the display, you must provide a definition of a monadic function, view or variable named `draw`. This will be invoked 30 times per second (see `tr`) and should return/consist of a list of tuples. Each tuple must contain a vector indicating an (x;y) position on screen, a palette and a bitmap. The palette consists of a list of strings representing any valid DOM color code such as "black" or "#FAC". The bitmap is a matrix of indices into the palette. By default, the display is 160x160 pixels. 14 | 15 | For example, the following definition of `draw` will draw a small blue on red box at a random position: 16 | 17 | draw: {,(2?w;("#00F";"#F00");(1111b;1001b;1001b;1111b))} 18 | 19 | Tuples will be drawn in the order they appear. For improved flexibility, any field of the tuple can be replaced with a symbol. Symbols will be looked up as variables when drawing. The above example could be rewritten as follows: 20 | 21 | p: 2?w 22 | c: ("#00F";"#F00") 23 | b: (1111b 24 | 1001b 25 | 1001b 26 | 1111b) 27 | draw: {,`p`c`b} 28 | 29 | Observe how in the first example the box is drawn at a different position every time, but in the second example it is drawn in a consistent position as `2?w` is only evaluated once and then stored. 30 | 31 | If the "position" element of any drawing tuple is a matrix instead of a vector, the bitmap will be drawn several times at each (x;y) pair. This makes it very easy to draw many identical objects simulatenously: 32 | 33 | draw: {,((5 5;30 5;18 20);`lcd;text@6)} 34 | 35 | If the "position" element is null, the bitmap will be drawn centered on the screen: 36 | 37 | draw: ,(;cga;50 30#2) 38 | 39 | If the "palette" element is null, the bitmap will be drawn using the built-in palette `cga`: 40 | 41 | draw: ,(;;t+\:t:3!-20!!160) 42 | 43 | If the "bitmap" element of any drawing tuple is a number or a vector, it will be drawn as a single pixel or a horizontal strip of pixels, respectively. Drawing single pixels in this way is generally quite inefficient, but drawing horizontal strips in combination with a vector of positions can produce some interesting "rasterbar" effects. 44 | 45 | If the tuple does not contain a bitmap, it represents drawing a filled polygon. The 0th palette color will be used for drawing the edges of the polygon (stroke) and the 1st palette color will be used to fill the polygon: 46 | 47 | draw: ,((10 10;20 10;15 20);cga@3 2) 48 | 49 | If you try to draw a polygon without specifying any coordinates, it represents clearing the screen. The following example will fill the screen with a red background: 50 | 51 | draw: ,(;("blue";"red")) 52 | 53 | Ticks 54 | ----- 55 | If you define a monadic function `tick`, it will be called periodically based on `tr`. Often this function will mutate surrounding state to be drawn by `draw`. The input to `tick` will, on the first frame of a program, be the contents of a variable named `once`, and the result of executing `tick` will then be stored in `once`. When `draw` is called, the value of `once` is likewise fed in. For convenience, if `once` is not explicitly initialized it will be treated as an empty list. Consider the following example: 56 | 57 | once: 10 15 58 | tick: {1 2+x} 59 | draw: {,(x;;5 5#3)} 60 | 61 | ![Tick Lifecycle](https://raw.githubusercontent.com/JohnEarnest/ok/gh-pages/ike/img/tick.png) 62 | 63 | By using this approach it is possible to write programs with evolving state using only _pure_ (side-effect free) definitions of `draw` and `tick`. 64 | 65 | Sound 66 | ----- 67 | To add sound to your programs, define a monadic function or variable named `play`. Sound playback further requires a definition of `draw`. iKe plays waveforms at a sample rate given by the variable `srate` with samples in the range [-1.0, 1.0]. If `play` is a list or scalar it will be repeated as necessary to supply continuous audio: 68 | 69 | draw: ,(;;) 70 | play: .2*?500 / a short noise sample 71 | 72 | If `play` is a function, it will be called with a single argument indicating the number of samples which have been produced since the program started. This function will be called periodically whenever the audio subsystem requires more samples. For best performance, it is a good idea to produce a number of samples on each call and return them as a list, rather than one at a time. Here's an example which plays a sine wave: 73 | 74 | draw: ,(;;) 75 | play: {.2*sin .2*x+!1000} 76 | 77 | Input Events 78 | ------------ 79 | For dynamic behavior, iKe will call a number of K functions (provided they have been defined) whenever certain events occur: 80 | 81 | - `kd`: key down. provides a DOM keyCode as an argument. 82 | - `ku`: key up. provides a DOM keyCode as an argument. 83 | - `kx`: key typed. provides a DOM charCode as an argument. 84 | - `kr`: return/enter pressed. Provides 10 as an argument (to match `kx`). 85 | - `kb`: backspace pressed. Provides 8 as an argument (to match `kx`). 86 | - `lx`: left/right. provides -1/1 when left/right cursor keys are pressed. 87 | - `ux`: up/down. provides -1/1 when up/down cursor keys are pressed. 88 | - `md`: mouse down. provides mouse x and y in pixels as arguments. 89 | - `mu`: mouse up. provides mouse x and y in pixels as arguments. 90 | - `mm`: mouse moved. provides mouse x and y in pixels as arguments. 91 | - `mg`: mouse dragged. provides mouse x and y in pixels as arguments. 92 | 93 | Built-in Functions 94 | ------------------ 95 | iKe extends the basic k5 intrinsics `sin` `cos` `log` and `exp` with a broader range of math and utility functions: 96 | 97 | - `abs`: monadic. absolute value. 98 | - `tan`: monadic. tangent. 99 | - `acos`: monadic. inverse cosine. 100 | - `asin`: monadic. inverse sine. 101 | - `atan`: monadic. inverse tangent. 102 | - `cosh`: monadic. hyperbolic cosine. 103 | - `sinh`: monadic. hyperbolic sine. 104 | - `tanh`: monadic. hyperbolic tangent. 105 | - `pow`: dyadic. raise x to the y power. 106 | - `atan2`: dyadic. version of arctangent which disambiguates quadrants. 107 | - `pn`: triadic. 3d Perlin Noise generator. 108 | 109 | Variables 110 | --------- 111 | iKe pre-defines and updates several K variables for your convenience: 112 | 113 | - `w`: the width of the screen in pixels (read and write) 114 | - `h`: the height of the screen in pixels (read and write) 115 | - `f`: counts up once for each drawn frame (read only) 116 | - `dir`: a 2d vector with the (x;y) offset of the cursor keys currently held (read only) 117 | - `keys`: a vector of the keycodes currently held (read only) 118 | - `mx`: the horizontal position of the mouse in pixels (read only) 119 | - `my`: the vertical position of the mouse in pixels (read only) 120 | - `pi`: the mathematical constant Pi (read only) 121 | - `tr`: tick rate; how many times per second `tick` and `draw` are fired (read and write) 122 | - `fc`: when recording an animated GIF, the number of frames to render. (read and write) 123 | 124 | iKe provides a number of pre-defined palettes. Since transparency is useful, the last color of most palettes is fully transparent: 125 | 126 | - `cga`: CGA palette 1 (4 colors + transparency) 127 | - `hot`: hot dog stand (4 colors + transparency) 128 | - `lcd`: Similar to the pea-soup LCD display of the GameBoy (4 colors + transparency) 129 | - `solarized`: The [solarized](http://ethanschoonover.com/solarized) palette. (16 colors + transparency) 130 | - `dawnbringer`: [dawnbringer's](http://pixeljoint.com/forum/forum_posts.asp?TID=12795) pixel art palette. (16 colors + transparency) 131 | - `windows`: Windows 3.1 palette (16 colors + transparency) 132 | - `arne`: [Arne's](http://androidarts.com/palette/16pal.htm) Generic 16 color game palette. (16 colors + transparency) 133 | - `pico`: The [PICO-8](http://www.lexaloffle.com/pico-8.php) fantasy game console's 16 color palette. (16 colors + transparency) 134 | - `gray`: Grayscale, black to white. (256 colors) 135 | 136 | ![palettes](https://raw.githubusercontent.com/JohnEarnest/ok/gh-pages/ike/img/swatches.png) 137 | 138 | iKe also provides a built-in 8x8 character set called `text`: 139 | 140 | ,(;cga;~,/'+text"Hello, World!") 141 | 142 | The character set is aligned with 7-bit ASCII and control characters are replaced with some useful graphic characters including symbols and box drawing characters: 143 | 144 | ![font](https://raw.githubusercontent.com/JohnEarnest/ok/gh-pages/ike/img/font.png) 145 | 146 | External Resources 147 | ------------------ 148 | Sometimes you may wish to include large resources in a sketch without creating a bulky matrix literal. iKe has a facility for loading images from a specified URL. Create a comment at the beginning of a line which starts with "/i" to load an image. After "/i", specify the name you wish to give the image, a semicolon, the name of a built-in palette, a semicolon and then the URL where the image may be found. 149 | 150 | When your program is run, these special comments will be processed and the resources will be unpacked into K's environment. iKe makes a best-effort (least sum-of-squares per-channel difference) attempt at converting colors in the image into the specified palette when it is loaded. 151 | 152 | /i blu;solarized;http://i.imgur.com/IVfDjMj.png 153 | draw: ,(0 0;`solarized;`blu) 154 | 155 | Note that image loading _only_ works with built-in palettes- image loading happens before any of your K code has a chance to execute! 156 | 157 | Ajax 158 | ---- 159 | Your programs can perform asynchronous HTTP requests to remote servers which return appropriate CORS headers. The `ajax` function takes three arguments: a URL, an HTTP verb and some K monad which will be called with the result of the request when it becomes available. Server response bodies will be parsed as JSON and then converted into convenient K data structures. 160 | 161 | ajax["http://www.com/api.json";"GET";{ dosomething x }] 162 | 163 | Animated GIFs 164 | ------------- 165 | The "record" button asks iKe to render an animated GIF of the program's output. The result will have `fc` frames, which will each have an interframe delay which respects `tr`. Note that the resulting GIFs may be very large- consider running them through an optimizer like [Gifsicle](https://www.lcdf.org/gifsicle/). 166 | -------------------------------------------------------------------------------- /ike/audio.js: -------------------------------------------------------------------------------- 1 | 2 | // HTML5 Audio realtime synthesis 3 | 4 | var SAMPLE_MULT = 4; 5 | var sampleCount = 0; 6 | var sampleRem = 0; 7 | var sampleIndex = 0; 8 | var bufferedAudio = []; 9 | 10 | function getAudioSample() { 11 | // multiply samples out: 12 | if (sampleRem == SAMPLE_MULT-1) { sampleRem = 0; sampleIndex++; } 13 | else { sampleRem++; } 14 | 15 | // fetch more samples from K if we're out of buffered ones: 16 | if (sampleIndex >= bufferedAudio.length) { 17 | var samples = null; 18 | var playval = env.lookup(ks("play")); 19 | if (playval.t == 3) { 20 | samples = playval; 21 | } 22 | else { 23 | samples = callk1("play", sampleCount); 24 | if (samples.t == 0) { samples = k(3, [samples]); } 25 | } 26 | sampleCount += len(samples); 27 | bufferedAudio = []; 28 | sampleIndex = 0; 29 | for(var z = 0; z < len(samples); z++) { 30 | bufferedAudio.push(samples.v ? samples.v[z].v : 0); 31 | } 32 | } 33 | 34 | // discharge a sample from our prepared buffer: 35 | return bufferedAudio[sampleIndex]; 36 | } 37 | 38 | var audio; 39 | var soundSource; 40 | var scriptNode; 41 | 42 | function audioSetup() { 43 | if (audio && soundSource) { return true; } 44 | if (!audio) { 45 | if (typeof AudioContext !== 'undefined') { 46 | audio = new AudioContext(); 47 | } 48 | else if (typeof webkitAudioContext !== 'undefined') { 49 | audio = new webkitAudioContext(); 50 | } 51 | } 52 | if (audio) { 53 | scriptNode = audio.createScriptProcessor(4096, 1, 1); 54 | scriptNode.onaudioprocess = function(audioProcessingEvent) { 55 | var inputBuffer = audioProcessingEvent.inputBuffer; 56 | var outputBuffer = audioProcessingEvent.outputBuffer; 57 | for(var channel = 0; channel < outputBuffer.numberOfChannels; channel++) { 58 | var inputData = inputBuffer.getChannelData(channel); 59 | var outputData = outputBuffer.getChannelData(channel); 60 | if (env.contains(ks("play"))) { 61 | setvar("srate", num(Math.floor(outputBuffer.sampleRate / SAMPLE_MULT))); 62 | for(var sample = 0; sample < inputBuffer.length; sample += 1) { 63 | outputData[sample] = getAudioSample(); 64 | } 65 | } 66 | } 67 | } 68 | return true; 69 | } 70 | return false; 71 | } 72 | 73 | function audioPlay() { 74 | if (running && audioSetup()) { 75 | sampleCount = 0; 76 | sampleRem = 0; 77 | sampleIndex = 0; 78 | bufferedAudio = []; 79 | soundSource = audio.createBufferSource(); 80 | soundSource.buffer = audio.createBuffer(1, 4096, audio.sampleRate); 81 | soundSource.connect(scriptNode); 82 | scriptNode.connect(audio.destination); 83 | soundSource.loop = true; 84 | soundSource.start(0); 85 | } 86 | } 87 | 88 | function audioStop() { 89 | if (soundSource != null) { 90 | scriptNode.disconnect(); 91 | soundSource.loop = false; 92 | soundSource.disconnect(); 93 | soundSource = null; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ike/examples/ajax.k: -------------------------------------------------------------------------------- 1 | / retrieve the current 'value' of Bitcoin 2 | / via an AJAX/JSON web API provided by CoinDesk.com 3 | 4 | url: "https://api.coindesk.com/v1/bpi/currentprice.json" 5 | ajax[url;"GET";{time:: -12#x[`time][`updated] 6 | price:: x[`bpi][`GBP][`rate]}] 7 | 8 | time: "--:--:-- UTC" 9 | price: "---.---" 10 | pr: ~,/'+text@ 11 | draw:: ((10 10;cga;pr "Bitcoin Price At") 12 | (10 20;cga;pr time) 13 | (10 30;cga;pr "$",price)) 14 | -------------------------------------------------------------------------------- /ike/examples/asteroids.k: -------------------------------------------------------------------------------- 1 | / left/right=steer up=thrust down=fire 2 | wh:(w;h);C:wh%2 / dimensions and centre of universe 3 | trg:(cos;sin)@\:;sq:{x*x} / helper functions 4 | Sp:C;Sv:0 0;Sh:0 / spaceship's position, velocity, and heading 5 | An:3;As:An#3;Av:+trg.0628*An?100 / asteroids: number, sizes, velocities 6 | Ap:C+/:(&/C)*+trg.0628*An?100 / asteroid positions 7 | Bp:Bv:Bt:() / bullets' positions, velocities, times left (in ticks) 8 | Br:0 / time until spaceship can fire again (in ticks) 9 | P:("#000";"#fff";"#888";"#f00";"#00f") / palette 10 | msg:" " / message 11 | draw:{ 12 | t:trg Sh;T:-1 1*|t 13 | r:(,:'Sp+/:(2*t;-t;T-2*t;-T+2*t)),\:(P;1) / spaceship 14 | r,:,(Sp-2*t;P;3*0>dir 1) / exhaust fire 15 | r,:(,:'Ap-As%2),'`P,',:'(2#'As)#'2 / asteroids 16 | r,:(,:'Bp),\:(P;4) / bullets 17 | r,:,(0 0;P;~,/'+text@`i$msg) 18 | } 19 | tick:{ 20 | $[~#Ap;(msg::"you win";tick::{});0] / no asteroids left? 21 | $[|/0,25>+/'sq Sp-/:Ap;(msg::"you lose";tick::{});0] / spaceship-asteroid collision 22 | Sh+::.1**dir / steer 23 | Sv+::(trg Sh)*.1*0>dir 1 / thrust 24 | Sp::wh!'Sp+Sv / move spaceship 25 | Ap::wh!'/:Ap+Av / move asteroids 26 | Bp::wh!'/:Bp+Bv / move bullets 27 | $[(~Br)&00;Bp@::i;Bv@::i;Bt@::i / rm expired and impacting bullets 30 | m:&/'c;i:&m;j:&2*~m|As=1 / indices of surviving(i) and splitting(j) asteroids 31 | Ap::Ap i,j;Av::(Av i),((#j)#(1 -1;-1 1))*|:'Av j;As::(As i),-1+As j 32 | } 33 | fire:{Bp,::,Sp+3*trg Sh;Bv,::,1.5*trg Sh;Bt,::100;Br::10} 34 | -------------------------------------------------------------------------------- /ike/examples/bounce.k: -------------------------------------------------------------------------------- 1 | / bouncing ball demo: 2 | 3 | back: w#'h#+0,+0,7 7#1 4 | ball: (4 4 2 2 2 4 4 5 | 4 2 2 2 1 2 4 6 | 2 2 2 2 2 2 2 7 | 2 2 2 2 2 2 2 8 | 2 2 2 2 2 2 2 9 | 4 2 2 2 2 2 4 10 | 4 4 2 2 2 4 4) 11 | 12 | dim: (w;h)-7 13 | org: 0 0 14 | pos: 10 10 15 | vel: 2 5 16 | 17 | tick: {pos::vel+0|dim&pos 18 | vel*::1 -1(pos<0)|pos>dim} 19 | 20 | draw: (`org `solarized `back 21 | `pos `hot `ball) 22 | -------------------------------------------------------------------------------- /ike/examples/brownian.k: -------------------------------------------------------------------------------- 1 | / brownian motion demo 2 | / click to add more people 3 | 4 | guy: 7#7#'2+text@6 5 | once: ,(w;h)%2 6 | md: {once,::,x,y} 7 | tick: {w!x+0N 2#(2*#x)?-1 0 1} 8 | draw: {,(x;;guy)} 9 | -------------------------------------------------------------------------------- /ike/examples/checker.k: -------------------------------------------------------------------------------- 1 | / based on http://chessboardifygame.xyz 2 | 3 | T: 30 / tile size 4 | D: 3 3 / board dimensions 5 | b: D#(*/D)?2 / random initial grid 6 | h:w: T*#b / set display size 7 | adj: {.[D#0;(D-1)&0|(x-1)+!3 3;1]} / adjacent cells to position x 8 | md: {b::~b=adj@_(x;y)%T} / xor board with adjacency mask from click 9 | done:: (b~+b)&&//(~=)':b / is the board chessboardified? 10 | tile:: ,/'+,/'((2#T)#)''2*b / draw the board as tiles 11 | draw:: ,(0 0;solarized;(8*done)+tile) 12 | -------------------------------------------------------------------------------- /ike/examples/cursor.k: -------------------------------------------------------------------------------- 1 | / cursor movement demo 2 | 3 | ball: (0 0 2 2 2 0 0 4 | 0 2 2 2 1 2 0 5 | 2 2 2 2 2 2 2 6 | 2 2 2 2 2 2 2 7 | 2 2 2 2 2 2 2 8 | 0 2 2 2 2 2 0 9 | 0 0 2 2 2 0 0) 10 | 11 | once: _-3+(w;h)%2 12 | tick: {0|((w;h)-7)&x+3*dir} 13 | draw: {,(x;hot;ball)} 14 | -------------------------------------------------------------------------------- /ike/examples/dissolve.k: -------------------------------------------------------------------------------- 1 | 2 | / animation effect demo: dissolve in 3 | 4 | /i crate;lcd;http://i.imgur.com/lmVpqLA.png 5 | 6 | d: (#*crate;#crate) / dimensions of the image 7 | s: */d / pixel count of the image 8 | px: ,/+crate / pixels of the image 9 | ri: _0.5*|/d / radius of the image 10 | rr: ri*?s / random radii 11 | ra: pi*2*?s / random angles 12 | p2c: {x*(cos y;sin y)} / polar (r;a) to cartesian (x;y) 13 | rc: rr p2c'ra / random coordinates scattered in a circle 14 | ic: (+!d)-\:_d%2 / coordinates of each pixel of the image 15 | 16 | dur: 30 / tween duration in frames 17 | eas: {1+t*t*t:x-1} / cubic ease out 18 | int: {(x*1-i)+y*i:eas(f&dur)%dur} / eased interpolation from x to y 19 | 20 | c: (.5*(w;h))+/: / center and snap coordinates on screen 21 | pnt: {(y;lcd;x)} / draw a point at pos y in color x 22 | 23 | / draw each pixel of the image as a point at 24 | / the centered result of interpolating between 25 | / the scattered positions and final positions: 26 | 27 | draw: { px pnt'c int[rc;ic] } 28 | -------------------------------------------------------------------------------- /ike/examples/distance.k: -------------------------------------------------------------------------------- 1 | / 2D Distance Fields 2 | / (and a few shader primitives) 3 | 4 | len: {%+/x*x} / length of vector 5 | sstep: {(3-2*t)*t*t:0|1&(z-x)%y-x} / smoothstep (a;b;tween) 6 | trans: {x-y} / (pos;offset) 7 | scale: {x%y} / (pos;scale) 8 | rot: {t:(cos;sin)@\:y;(+/t*x;-/t*|x)} / (pos;rads) 9 | circ: {(-y)+len x} / (pos;radius) 10 | rect: {(0&|/d)+o:len 0|d:abs[x]-y%2} / (pos;size) 11 | 12 | / rendering 13 | 14 | size: w 15 | grid: t,\:/:t:(-size%2)+!size 16 | field: {,(;gray;255&0|_16*x''grid)} / distance field itself 17 | waves: {,(;solarized;8!0|_x''grid)} / frontier waves of distance field 18 | hard: {,(;;0>x''grid)} / hard-edged object(s) 19 | 20 | / demo 21 | 22 | dist: {rect[rot[x;.5];20 40]&rect[x;10 100]&circ[x+20 20;17]} 23 | waves dist 24 | -------------------------------------------------------------------------------- /ike/examples/economy.k: -------------------------------------------------------------------------------- 1 | / Brownian Economy 2 | 3 | / "Imagine a room full of 100 people with 100 dollars each. 4 | / With every tick of the clock, every person with money gives 5 | / a dollar to one randomly chosen other person. After some 6 | / time progresses, how will the money be distributed?" 7 | 8 | p: 72 / players 9 | c: {(+/(!#x)=/:(+/t)?#x)-t:0t{%(x*x)+y*y}\:t:|!x} 4 | ew: 4 1@cir[20] 5 | ep: 4 3@cir[10] 6 | 7 | eye: {a: atan2.(my;mx)-|x 8 | ((x-20;cga;ew) 9 | ((x-10)+_10*(cos a;sin a);cga;ep))} 10 | 11 | draw: {,/eye'(60 100;100 100;80 65)} -------------------------------------------------------------------------------- /ike/examples/hexagons.k: -------------------------------------------------------------------------------- 1 | / HexScape 2 | / adapted from https://gist.github.com/JohnEarnest/9147835 3 | / which in turn was based on a GIF I found somewhere... 4 | 5 | hex: {+x*(cos;sin)@\:(pi%3)*!7} / radius -> hex 6 | hole: {(hex x),|hex y} / (outer;inner) -> poly 7 | pulse: { / anim offset -> poly 8 | e:1+e*e*e:-1+1! a:2!x+.02*f / ease, anim timer 9 | hole.$[a>1;30*1,e;e*30 0] / eased holes 10 | } 11 | 12 | warp: { / fisheye warp (x;y) by z 13 | r:%+/(x*x;y*y) / polar radius 14 | a:atan2[y;x] / polar angle 15 | (cos a;sin a)*\:s*tanh r%s:w*z / hyperbolic, -> cartesian 16 | } 17 | 18 | hv: 30*cos pi%6 / vertical offset (radius 30) 19 | hh: 2*hv*cos pi%6 / horizontal offset 20 | grid: +2-!5 5 / {[-2,2],[-2,2]} 21 | hgrid: ,/{(2*hh*x;2*hv*y)-/:(0 0;hh,hv)}.'grid / hex origins 22 | offs: 4 0N#2*?4*#hgrid / animation offsets 23 | 24 | zd: 1.7 1.4 1.1 1.0 25 | pal: ("#21FFF2";"#FF7F00";"#FB0007";"#1E1400";"#00000000") 26 | place: {(+80+warp[;;zd x].y++pulse[z];pal 4,x)} / place hex at (z;pos;off) 27 | draw: {,/{place[x]'[hgrid;offs x]}'!4} / draw all layers 28 | 29 | w:h: 160; fc: 100 30 | -------------------------------------------------------------------------------- /ike/examples/hyperplane.k: -------------------------------------------------------------------------------- 1 | / Hyperplane 2 | 3 | dist: {%(x*x)+y*y} / cartesian distance 4 | c2p: {(dist;atan2).\:(y;x)} / cartesian (x;y) to polar (r;a) 5 | p2c: {(x*sin y;x*cos y)} / polar (r;a) to cartesian (x;y) 6 | fish: p2c.{(tanh x;y+f*.02)}.c2p. / fisheye distortion 7 | 8 | grid: 0.2*(!21 21)-10 10 / grid of points in [-2,2] space 9 | any: {-2+4*?2} / random point in [-2,2] space 10 | goal: any[] / where are we going 11 | pos: 0 0 / where are we now 12 | mark: text"x" / goal icon 13 | 14 | tick: {pos+::.05* d:goal-pos / move toward goal 15 | goal::$[.1>dist.d;any[];goal]} / pick new goal when we're close 16 | draw:: ((+80+80*fish grid-pos;cga;2) / draw the grid 17 | ( 76+80*fish goal-pos;cga@3 4;mark)) / draw the goal 18 | -------------------------------------------------------------------------------- /ike/examples/ikeanoid.k: -------------------------------------------------------------------------------- 1 | / iKeanoid 2 | 3 | br: 4(+|2,)/6 14#3 2 3 / brick sprite 4 | bp: +16 8*!10 5 / brick positions (x;y) 5 | bl: {x,|x}'e:{x,|x}(001b;011b;111b) / ball sprite 6 | pl: 3*e{x,y,|x}'6 58#1 / paddle sprite 7 | p: _.5*w,h / ball position 8 | v: 2 -3 / ball velocity 9 | ba: (#bp)#1 / bricks alive? 10 | 11 | r: {(z>x)&z1;rz[x].\:y-1;F[]]} / recursively apply a rule 7 | s: 0N 2#(^)_ / filter rotates out of vertex list 8 | dim: {(|/'x)-&/'x}@+ / dimensions of the polygon 9 | scl: w%|/dim@ / rescale polygon 10 | off: {(.5*w-dim x)-&/'+x} / offset polygon 11 | cnt: {+off[t]++t:x*scl x} / center polygon 12 | 13 | / sierpinski gasket 14 | t: pi*2%3 / turn angle 15 | rz: [R:{d+::t;0N} / move the turtle right 16 | L:{d-::t;0N} / move the turtle left 17 | a:r `a`L`b`R`a`R`b`L`a 18 | b:r `b`b] 19 | 20 | / animate 21 | shape: cnt s rz[`a]6 22 | wiggle: {x+0N 2#1.3*(?2*#x)-.5} 23 | draw:: ,(((#shape)!f)#wiggle shape;cga@2 3) 24 | -------------------------------------------------------------------------------- /ike/examples/lorenz.k: -------------------------------------------------------------------------------- 1 | / Lorenz Attractor 2 | 3 | s: 0.008 / step size 4 | c: 10 28 2.666 / constants 5 | p: 0 10 10 / start position 6 | i: 5000 / iteration count 7 | 8 | iter: {x+s*(c[0]*x[1]-x[0] 9 | (x[0]*(c[1]-x[2]))-x[1] 10 | (x[0]*x[1])-c[2]*x[2])} 11 | 12 | ,((80+3*i iter\0 10 10)[;0 1];;1) 13 | -------------------------------------------------------------------------------- /ike/examples/mandelbrot.k: -------------------------------------------------------------------------------- 1 | / mandelbrot set renderer 2 | xr: -2 .5 / horizontal interval 3 | yr: -1.2 1.2 / vertical interval 4 | 5 | r: {(&/x)+((-/|x)%w)*!w} / sample range 6 | m: {x+(-/y*y;2**/y)} / mandelbrot iteration 7 | i: {+/{4>+/x*x}'15 m[x]\0} / iterate to convergence 8 | c: (r xr),/:\:r yr / screen point coordinates 9 | 10 | ,(;|arne;i''c) 11 | -------------------------------------------------------------------------------- /ike/examples/musicplayer.k: -------------------------------------------------------------------------------- 1 | / note transcription 2 | / C-3 C#3 D-3 D#3 E-3 F-3 F#3 G-3 G#3 A-3 A#3 B-3 3 | / 1 2 3 4 5 6 7 8 9 10 11 12 4 | / C-4 C#4 D-4 D#4 E-4 F-4 F#4 G-4 G#4 A-4 A#4 B-4 5 | / 13 14 15 16 17 18 19 20 21 22 23 24 6 | 7 | m1: 4 0 9 0 4 0 9 0 3 0 9 0 3 0 9 0 4 0 4 0 1 0 9 0 8 | m2: 1 0 9 0 1 0 2 3 9 | m3: 12 0 11 0 9 0 0 0 10 | h1: 21 21 0 21 21 0 0 0 21 21 0 21 21 0 0 0 21 21 0 21 21 0 19 21 11 | h2: 21 19 1 1 21 21 21 0 12 | song: +(m1,m2,m1,m3; h1,h2,h1,h2) 13 | 14 | / synthesizer 15 | note: {440*pow[2;x%12]} / freq. relative to a4 16 | freq: 0,note'-21+!24 / two octaves starting at c3 17 | gain: 0.25 / volume scale 18 | tempo: 1500 / samples per note 19 | mix: {wave::(+/x)%#x} / blend waveforms and stash a copy 20 | osi: { sin x*2*pi*y%srate} / sine oscillator 21 | osq: {_.5+sin x*2*pi*y%srate} / square oscillator 22 | ost: { 1! x* y%srate} / sawtooth oscillator 23 | step: {freq@song@(#song)!_x%tempo} / frequencies of a step in the song 24 | play: {gain*mix@((ost;osi)@'step x)@\:x+!500} / generate blended waveform 25 | 26 | / simple waveform viewer 27 | wave: h#0 28 | draw: {+((_(w%2)*1+h#wave),'!h;,cga;,w#1)} 29 | -------------------------------------------------------------------------------- /ike/examples/paint.k: -------------------------------------------------------------------------------- 1 | / painting program demo 2 | 3 | img: (w;h)#0 4 | col: 1 5 | mg: {img[y;x]::col} 6 | ux: {col::4!col+x} 7 | draw: ,(;`cga;`img) 8 | -------------------------------------------------------------------------------- /ike/examples/palette.k: -------------------------------------------------------------------------------- 1 | / built-in palette demo: 2 | 3 | h: 178 4 | w: 130 5 | sml: +16#'&4#32 6 | lrg: +16#'&16#8 7 | ((1 1;`cga ;`sml) 8 | (1 21;`hot ;`sml) 9 | (1 41;`lcd ;`sml) 10 | (1 61;`solarized ;`lrg) 11 | (1 81;`dawnbringer;`lrg) 12 | (1 101;`windows ;`lrg) 13 | (1 121;`arne ;`lrg) 14 | (1 141;`pico ;`lrg) 15 | (1 161;`gray ;16#,2*!128)) -------------------------------------------------------------------------------- /ike/examples/plasma.k: -------------------------------------------------------------------------------- 1 | / perlin plasma 2 | 3 | size: 30 4 | grid: t{x,y}\:/:t:(!size)%10 5 | draw: {,(;solarized;_8*pn[f%50].''grid)} 6 | -------------------------------------------------------------------------------- /ike/examples/poisson.k: -------------------------------------------------------------------------------- 1 | / Poisson Disk Sampling 2 | / This algorithm is intended for generating sets of 3 | / randomly but semi-uniformly distributed points. 4 | 5 | spread: 10 / minimum distance between points 6 | density: 1 / how many points per round (>1 produces clumps) 7 | rounds: 200 / how many times do we expand the set 8 | 9 | annulus: {(spread;2*pi)*1 0+?2} / ring around origin 10 | p2c: {x*(cos y;sin y)} / (radius;angle) 11 | around: {(x+p2c.)'annulus'!density} / nearby points 12 | dist: {%+/'{x*x}x-/:y} / (center;points) 13 | more: {x,({spread<&/dist[y;x]}[x])#around[*1?x]} / expand point set 14 | poisson: rounds more/,80 80 15 | 16 | ,(poisson;cga;1) 17 | -------------------------------------------------------------------------------- /ike/examples/raster.k: -------------------------------------------------------------------------------- 1 | / Raster Graphics Helpers 2 | 3 | dim: -1_#:'*:\ / rectangular shape/dimensions of x 4 | grid: ,/'+,/'+ / bitmap from grid of uniform tiles 5 | scale: {2(+(,/x#')')/y} / scale up bitmap y by x 6 | pad: {(x#y)*(#y)>!x} / make y length x, padding with 0 7 | crop: {{+pad[y]'+pad[z]'x}[y].x} / make y dimension x, padding with 0 8 | tess: {{y#z#'x}[y].x} / make y dimension x, tesselating bitmap 9 | full: {,((w|h)*2 2\'0 1 3 2;("";x))} / background color x 10 | -------------------------------------------------------------------------------- /ike/examples/sierpinski.k: -------------------------------------------------------------------------------- 1 | / monte carlo sierpinski triangle 2 | 3 | i: {*1?(0;.5;1 0)+\:x%2} 4 | tick: {x,,_80*20i/1 1} 5 | draw: {,(x;;3)} 6 | -------------------------------------------------------------------------------- /ike/examples/small.k: -------------------------------------------------------------------------------- 1 | 2 | / trail 3 | spr: 1+,/'+text"oK" 4 | pos: 50 2#100?w 5 | mm: {pos::50#(,x,y),pos} 6 | tick: {pos::w!pos+(#pos;2)#(2*#pos)?-1 0 1} 7 | draw: {,`pos`lcd`spr} 8 | 9 | / vortex 10 | bmp: {x,|x}'{x,|x}t{_%(x*x)+y*y}\:t:|!80 11 | pal: (|t),t:8#solarized 12 | draw: {,(;`pal;(#pal)!bmp+f)} 13 | 14 | / marching ants 15 | 16 | edge: {|+(4!f+!#x),'x} 17 | draw: {,(;`cga;4 edge/64 64#0)} 18 | 19 | / word vortex 20 | 21 | bobs: 2+text"We Like iKe" 22 | words: {+({,_80+60*(cos x;sin x)}'.5*(.1*f)+!11;`cga;bobs)} 23 | bmp: {x,|x}'{x,|x}t{_%(x*x)+y*y}\:t:|!70 24 | pal: (|t),t:8#solarized 25 | vortx: {,(;`pal;(#pal)!bmp+f)} 26 | draw: {vortx[],words[]} 27 | 28 | / keyboard tester 29 | 30 | draw:: ,(;cga;30#,2+|/(-1,keys)=\:!128) 31 | 32 | / fermat spiral 33 | 34 | fs: {(%t)*(sin t;cos t:137.508*x)}'! 35 | draw: {,(80+.2*fs f;`lcd;2)} 36 | -------------------------------------------------------------------------------- /ike/examples/snake.k: -------------------------------------------------------------------------------- 1 | / SnaKe 2 | pr: {(x'!#y){x,,y}'~text y} 3 | pd: {(x+_ 8 5*y,cos .1*y+f;cga)} 4 | pt: {(26 60 +_20 8*x,sin x+.3*f;pico 16,8+x)} 5 | tl: {`setup`title@~+/dir} 6 | td: {pr[pt;"SnaKe!"],pr[pd[20 120];"Press arrows..."]} 7 | ol: {tr::30;`setup`over@~+/dir} 8 | od: {pr[pd[35 60];"Game Over!"],pr[pd[20 120];"Score: ",-8$$(l-7)%2]} 9 | 10 | sd: {,(;;)} 11 | su: {p:: ,10 10 / pos of snake segments 12 | g:: *p / pos of goal 13 | d:: 0 1 / direction of snake 14 | l:: 5 / length of snake 15 | tr:: 7 / tick rate 16 | `game} / proceed to main game 17 | 18 | gl: {a: p~?p / not colliding with self? 19 | d:: a*(dir;d)@~+/dir / update direction 20 | p:: (-l&1+#p)#p,,20!d+*|p / grow/move snake 21 | b: |/g~/:p / overlapping goal? 22 | g:: (g;2?20)b / respawn goal if needed 23 | l+:: 2*b / increment length if needed 24 | `game`over(~a)&1=#?p} / end if snake is totally dead 25 | 26 | wi: {_({(sin x;cos x)}'f+2*!#x)+x} / snake wiggle 27 | gd: {((w*2 2\'0 1 3 2;pico 2 1) / background 28 | (wi 8*-1_p;c;text 48) / snake 29 | (8**|p;c:cga (2+p~?p),4;text 5) / head 30 | (8*g;cga 2 4;text 8))} / goal 31 | 32 | ss: `title 33 | s: [title:(tl;td);setup:(su;sd);game:(gl;gd);over:(ol;od)] 34 | tick: {ss::s[ss;0][]} 35 | draw: {s[ss;1][]} 36 | -------------------------------------------------------------------------------- /ike/examples/spin.k: -------------------------------------------------------------------------------- 1 | / liquid Karma 2 | 3 | p2c: {x*(cos y;sin y)} / polar to cartesian 4 | slice: .0157*!100 / a quarter circle of radians 5 | arc: {80++p2c[x]slice+y} / centered points of a slice at a radius and offset 6 | wind: {arc[y*3]x+y*0.01*f} / scale arc radius and offset by frame counter 7 | curve: {,/wind[x]'1+!20} / a wedge of windings 8 | 9 | draw: {((curve[ 0];cga;2) 10 | (curve[pi];cga;3))} 11 | -------------------------------------------------------------------------------- /ike/examples/terminal.k: -------------------------------------------------------------------------------- 1 | / a terminal interface 2 | 3 | s: "" 4 | lines:: {(20|#x)$x}'"\n"\s,"_",399#" " 5 | term:: 1+,/'+,/'+text@20 20#,/lines,,"" 6 | 7 | kx:kr: {s,::`c$x} 8 | kb: {s::-1_s} 9 | draw: ,(;`lcd;`term) 10 | -------------------------------------------------------------------------------- /ike/examples/tiles.k: -------------------------------------------------------------------------------- 1 | / tile engine demo 2 | 3 | grid: (0 0 0 0 0 0 0 0 0 0 4 | 0 1 0 1 1 1 1 1 0 0 5 | 0 1 1 1 0 1 0 1 0 0 6 | 0 1 0 0 0 1 0 1 1 1 7 | 0 1 1 0 0 1 0 0 0 1 8 | 0 0 1 0 0 0 0 0 0 1 9 | 0 0 1 1 1 1 1 1 0 1 10 | 0 0 0 0 1 0 0 1 0 1 11 | 0 0 1 1 1 1 1 1 0 1 12 | 0 0 0 0 0 0 0 1 1 1) 13 | grid: {x,|x}'{x,|x} grid 14 | back: 2*,/'+,/'+(text@3 2)@grid 15 | guy: 2*text@6 16 | 17 | pos: 1 1 18 | tick: {pos+::dir*grid.|pos+dir} 19 | draw:: ((;solarized;back);(8*pos;hot;guy)) 20 | -------------------------------------------------------------------------------- /ike/examples/triangles.k: -------------------------------------------------------------------------------- 1 | / Positive-Negative Triangles 2 | 3 | ang: 2*pi%3 / triangle third 4 | rad: 20 / triangle radius 5 | fc: 200 / frames in anim 6 | sp: .01 / speed 7 | 8 | / draw and animate a triangle 9 | tri: {+x*(cos;sin)@\:y+ang*!3} / (radius;angle) 10 | spin: { / 1:left, -1:right 11 | a:2!sp*f; c:x~-1; b:c*pi 12 | r:b+(2*ang)*x*.5*1-cos pi*1!a 13 | tri.$[c=1 2 | 3 | iKe: powered by oK 4 | 5 | 6 | 118 | 119 | 120 |
121 |
122 | 123 |
124 |
125 |
126 |
127 | 128 |
129 |
130 | 131 |
132 |
133 | 134 |
135 |
136 | 137 |
138 | 139 | Documentation 140 | 143 | 148 |
149 |
150 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 880 | 881 | 882 | -------------------------------------------------------------------------------- /ike/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/close.png -------------------------------------------------------------------------------- /ike/img/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/font.png -------------------------------------------------------------------------------- /ike/img/full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/full.png -------------------------------------------------------------------------------- /ike/img/gist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/gist.png -------------------------------------------------------------------------------- /ike/img/livecoding.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/livecoding.gif -------------------------------------------------------------------------------- /ike/img/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/play.png -------------------------------------------------------------------------------- /ike/img/record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/record.png -------------------------------------------------------------------------------- /ike/img/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/stop.png -------------------------------------------------------------------------------- /ike/img/swatches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/swatches.png -------------------------------------------------------------------------------- /ike/img/tick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/ike/img/tick.png -------------------------------------------------------------------------------- /ike/noise.js: -------------------------------------------------------------------------------- 1 | 2 | // 3d Perlin noise 3 | 4 | // unfold two copies of a permutation array, for easy cyclic indexing. 5 | // most implementations hardcode this table, but it's easy to generate with K: 6 | var pp = tojs(run(parse("512# buffer.push(x & 0xFF) 11 | const s = x => { b(x); b(x >> 8) } 12 | const t = x => x.split('').forEach(x => b(x.charCodeAt(0))) 13 | const c = (t,z) => { for (let x=0; x<1<>16); b(c>>8); b(c) } } 14 | 15 | t('GIF89a') // header 16 | s(width) 17 | s(height) 18 | b(0xF1) // global colortable, 8-bits per channel, 4 colors 19 | b(0) // background color index 20 | b(0) // 1:1 pixel aspect ratio 21 | c([0x000000,0xFFFFFF,0x00FFFF,0xFF00FF], 2) // CGA 22 | 23 | return { 24 | comment: text => { 25 | s(0xFE21) // comment extension block 26 | b(text.length) // payload size 27 | t(text) // payload 28 | b(0) // terminator 29 | }, 30 | loop: count => { 31 | s(0xFF21) // application extension block 32 | b(11) // name/version size 33 | t('NETSCAPE2.0') 34 | b(3) // payload size 35 | b(1) // data sub-block index 36 | s(count) // repeat count (0 is forever) 37 | b(0) // terminator 38 | }, 39 | frame: (colors,pixels,delay) => { 40 | const z = Math.ceil(Math.log(colors.length)/Math.log(2)) || 1 41 | 42 | s(0xF921) // graphic control extension 43 | b(4) // payload size 44 | b(4) // do not dispose frame 45 | s(delay) // n/100 seconds 46 | b(0) // no transparent color 47 | b(0) // terminator 48 | 49 | b(0x2C) // image descriptor 50 | s(0) // x offset 51 | s(0) // y offset 52 | s(width) 53 | s(height) 54 | b(0x80|(z-1)) // local colortable, 2^z colors 55 | c(colors, z) 56 | 57 | b(7) // minimum LZW code size 58 | for (let off = 0; off < pixels.length; off += 64) { 59 | b(1 + Math.min(64,pixels.length-off)) // block size 60 | b(0x80) // CLEAR 61 | pixels.slice(off, off+64).forEach(b) 62 | } 63 | b(0) // end of frame 64 | }, 65 | finish: _ => { b(0x3B); return buffer }, 66 | } 67 | } 68 | 69 | function colorDistance(x, y) { 70 | const r = ((x>>16)&0xFF) - ((y>>16)&0xFF), 71 | g = ((x>> 8)&0xFF) - ((y>> 8)&0xFF), 72 | b = ((x )&0xFF) - ((y )&0xFF) 73 | return (r*r)+(g*g)+(b*b) 74 | } 75 | 76 | function repalette(pixels) { 77 | // find all distinct colors and their frequency 78 | const hist={} 79 | pixels.forEach(x => { 80 | if (x in hist) { hist[x].c++ } 81 | else { hist[x]={c:1, v:x} } 82 | }) 83 | 84 | // cull uncommon colors > 127 by mapping them 85 | // to the closest available common color 86 | const byfreq=Object.values(hist).sort((x,y) => y.c - x.c) 87 | while(byfreq.length>127) { 88 | const e=byfreq.pop() 89 | let n=byfreq[0], nd=colorDistance(e.v, n.v) 90 | for (let x=1; x x.i = i) 97 | 98 | // rebuild the image based on the new palette 99 | return { 100 | pixels: pixels.map(x => hist[x].i), 101 | colors: byfreq.map(x => x.v), 102 | } 103 | } 104 | 105 | function record() { 106 | stop() 107 | env = extendedEnv() 108 | loadresources(function() { 109 | const code = editor.value 110 | try { 111 | setvars() 112 | run(parse(code), env) 113 | if (!env.contains(ks('draw'))) { throw new Error('no definition of draw.') } 114 | if (!env.contains(ks('fc'))) { throw new Error('no definition of fc (framecount).') } 115 | const framecount = env.lookup(ks('fc'), true).v 116 | const gif = gifBuilder(canvas.width, canvas.height) 117 | gif.comment('made with iKe on '+new Date().toISOString()) 118 | gif.loop() 119 | for (frame = 0; frame < framecount; frame++) { 120 | // draw/update 121 | setvars() 122 | paintValue(callko('draw', [getonce()])) 123 | setvars() 124 | env.put(ks('once'), true, callko('tick', [getonce()])) 125 | 126 | // produce GIF frame 127 | const pixels = [] 128 | const raw = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height) 129 | for(let z = 0; z < canvas.width*canvas.height; z++) { 130 | const p = (raw.data[z*4]<<16) | (raw.data[z*4+1]<<8) | (raw.data[z*4+2]) 131 | pixels.push(p) 132 | } 133 | const processed = repalette(pixels) 134 | gif.frame(processed.colors, processed.pixels, 0|(frameDelay()/10)) // frameDelay is in ms... 135 | } 136 | saveAs(new Blob([new Uint8Array(gif.finish())], {type: 'image/gif'}), 'recording.gif') 137 | showStatus('exported '+canvas.width+'x'+canvas.height+' GIF with '+framecount+' frame(s)') 138 | } 139 | catch(e) { 140 | console.log(e) 141 | showError('export GIF failed: '+e.message) 142 | } 143 | }) 144 | } 145 | -------------------------------------------------------------------------------- /ike/text.js: -------------------------------------------------------------------------------- 1 | // a simple 8x8 font in an embarassingly inefficient packing scheme: 2 | 3 | var pixelfont = tok([ 4 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 5 | [[1,1,0,1,1,1,0,1,],[0,1,1,1,0,1,1,1,],[1,1,0,1,1,1,0,1,],[0,1,1,1,0,1,1,1,],[1,1,0,1,1,1,0,1,],[0,1,1,1,0,1,1,1,],[1,1,0,1,1,1,0,1,],[0,1,1,1,0,1,1,1,],], 6 | [[1,0,1,0,1,0,1,0,],[0,1,0,1,0,1,0,1,],[1,0,1,0,1,0,1,0,],[0,1,0,1,0,1,0,1,],[1,0,1,0,1,0,1,0,],[0,1,0,1,0,1,0,1,],[1,0,1,0,1,0,1,0,],[0,1,0,1,0,1,0,1,],], 7 | [[0,0,1,0,0,0,1,0,],[1,0,0,0,1,0,0,0,],[0,0,1,0,0,0,1,0,],[1,0,0,0,1,0,0,0,],[0,0,1,0,0,0,1,0,],[1,0,0,0,1,0,0,0,],[0,0,1,0,0,0,1,0,],[1,0,0,0,1,0,0,0,],], 8 | [[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],], 9 | [[1,0,0,0,0,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,0,1,0,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,0,0,0,1,0,1,],[0,1,1,0,1,1,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 10 | [[1,0,0,0,0,0,1,1,],[0,0,0,0,0,0,0,1,],[0,0,1,0,1,0,0,1,],[0,0,0,0,0,0,0,1,],[0,0,1,1,1,0,0,1,],[0,0,0,1,0,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 11 | [[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[1,1,1,1,1,1,1,1,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[1,1,1,1,1,1,1,1,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],], 12 | [[1,0,0,1,0,0,1,1,],[0,0,0,0,0,0,0,1,],[0,0,0,0,0,0,0,1,],[0,0,0,0,0,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 13 | [[1,1,1,0,1,1,1,1,],[1,1,0,0,0,1,1,1,],[1,0,0,0,0,0,1,1,],[0,0,0,0,0,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 14 | [[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[0,0,1,1,0,0,1,1,],[0,0,1,1,0,0,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,0,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 15 | [[1,1,0,0,1,1,1,1,],[1,0,0,0,0,1,1,1,],[0,0,0,0,0,0,1,1,],[0,0,0,0,0,0,1,1,],[0,0,0,0,0,0,1,1,],[1,1,0,0,1,1,1,1,],[1,0,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 16 | [[1,1,1,0,1,1,1,1,],[1,1,0,0,0,1,1,1,],[1,0,0,0,0,0,1,1,],[0,0,0,0,0,0,0,1,],[1,1,0,0,0,1,1,1,],[1,1,0,0,0,1,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 17 | [[1,1,1,0,1,1,1,1,],[1,1,1,0,0,1,1,1,],[0,0,0,0,0,0,1,1,],[0,0,0,0,0,0,0,1,],[0,0,0,0,0,0,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 18 | [[1,1,0,0,0,1,1,1,],[1,1,0,0,0,1,1,1,],[1,1,0,0,0,1,1,1,],[0,0,0,0,0,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 19 | [[1,1,1,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[1,0,0,0,0,0,0,0,],[1,1,0,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 20 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 21 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 22 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,0,0,0,0,],[1,1,1,0,0,0,0,0,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 23 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,0,0,0,],[1,1,1,0,0,0,0,0,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 24 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],], 25 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],], 26 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,0,0,0,0,],[1,1,1,0,0,0,0,0,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],], 27 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,0,0,0,],[1,1,1,0,0,0,0,0,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],], 28 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[0,0,0,0,0,1,1,1,],[0,0,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 29 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[0,0,0,0,0,1,1,1,],[0,0,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 30 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 31 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 32 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[0,0,0,0,0,1,1,1,],[0,0,0,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],], 33 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[0,0,0,0,0,1,1,1,],[0,0,0,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],], 34 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],], 35 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[0,0,0,0,0,0,0,0,],[0,0,0,0,0,0,0,0,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],], 36 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 37 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 38 | [[1,1,1,1,1,1,1,1,],[1,0,0,1,0,0,1,1,],[1,0,0,1,0,0,1,1,],[1,1,0,1,0,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 39 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,1,1,0,1,1,],[1,0,0,0,0,0,0,1,],[1,1,0,1,1,0,1,1,],[1,0,0,0,0,0,0,1,],[1,1,0,1,1,0,1,1,],[1,1,1,1,1,1,1,1,],], 40 | [[1,1,1,1,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,0,1,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,1,1,0,1,1,],[1,1,0,0,0,0,1,1,],[1,0,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 41 | [[1,1,1,1,1,1,1,1,],[1,0,0,1,1,1,0,1,],[1,0,0,1,1,0,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,0,1,1,0,0,1,],[1,0,1,1,1,0,0,1,],[1,1,1,1,1,1,1,1,],], 42 | [[1,1,1,1,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,0,1,1,0,1,1,1,],[1,1,0,0,1,1,1,1,],[1,0,1,1,0,1,0,1,],[1,0,1,1,1,0,1,1,],[1,1,0,0,0,1,0,1,],[1,1,1,1,1,1,1,1,],], 43 | [[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 44 | [[1,1,0,0,0,1,1,1,],[1,0,0,0,1,1,1,1,],[1,0,0,1,1,1,1,1,],[1,0,0,1,1,1,1,1,],[1,0,0,1,1,1,1,1,],[1,0,0,0,1,1,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 45 | [[1,1,1,0,0,0,1,1,],[1,1,1,1,0,0,0,1,],[1,1,1,1,1,0,0,1,],[1,1,1,1,1,0,0,1,],[1,1,1,1,1,0,0,1,],[1,1,1,1,0,0,0,1,],[1,1,1,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 46 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,1,1,0,1,1,],[1,1,1,0,0,1,1,1,],[1,0,0,0,0,0,0,1,],[1,1,1,0,0,1,1,1,],[1,1,0,1,1,0,1,1,],[1,1,1,1,1,1,1,1,],], 47 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 48 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 49 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 50 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 51 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,0,1,],[1,1,1,1,1,0,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,0,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 52 | [[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[0,0,1,1,1,0,0,1,],[0,0,1,0,1,0,0,1,],[0,0,1,0,1,0,0,1,],[0,0,1,1,1,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 53 | [[1,1,1,1,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,0,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[0,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 54 | [[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[0,0,1,1,1,0,0,1,],[1,1,1,1,0,0,0,1,],[1,0,0,0,0,1,1,1,],[0,0,0,1,1,1,1,1,],[0,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 55 | [[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[0,1,1,1,1,0,0,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,0,0,1,],[0,1,1,1,1,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 56 | [[1,1,1,1,1,1,1,1,],[0,0,1,1,0,0,1,1,],[0,0,1,1,0,0,1,1,],[0,0,0,0,0,0,0,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 57 | [[1,1,1,1,1,1,1,1,],[0,0,0,0,0,0,1,1,],[0,0,1,1,1,1,1,1,],[0,0,0,0,0,0,1,1,],[1,1,1,1,1,0,0,1,],[1,1,1,1,1,0,0,1,],[0,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 58 | [[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[0,0,1,1,1,1,1,1,],[0,0,0,0,0,0,1,1,],[0,0,1,1,1,0,0,1,],[0,0,1,1,1,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 59 | [[1,1,1,1,1,1,1,1,],[0,0,0,0,0,0,0,1,],[0,0,1,1,1,0,0,1,],[1,1,1,1,0,0,0,1,],[1,1,1,0,0,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 60 | [[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[0,0,1,1,1,0,0,1,],[1,0,0,0,0,0,1,1,],[0,0,1,1,1,0,0,1,],[0,0,1,1,1,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 61 | [[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[0,0,1,1,1,0,0,1,],[0,0,1,1,1,0,0,1,],[1,0,0,0,0,0,0,1,],[1,1,1,1,1,0,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 62 | [[1,1,1,1,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 63 | [[1,1,1,1,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,0,1,1,1,1,1,],], 64 | [[1,1,1,1,0,0,1,1,],[1,1,1,0,0,1,1,1,],[1,1,0,0,1,1,1,1,],[1,0,0,1,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 65 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 66 | [[1,1,0,0,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,1,0,0,1,],[1,1,1,1,0,0,1,1,],[1,1,1,0,0,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 67 | [[1,0,0,0,0,0,0,1,],[0,0,0,1,1,0,0,0,],[0,0,1,1,0,0,0,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 68 | [[1,1,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,0,0,1,0,1,],[1,0,1,0,1,1,0,1,],[1,0,1,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 69 | [[1,1,1,0,1,1,1,1,],[1,1,0,1,0,1,1,1,],[1,1,0,1,0,1,1,1,],[1,0,1,1,1,0,1,1,],[1,0,0,0,0,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 70 | [[0,0,0,0,0,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,0,0,0,0,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 71 | [[1,1,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[1,0,1,1,1,1,0,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 72 | [[0,0,0,0,0,1,1,1,],[0,1,1,1,1,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,0,1,1,],[0,0,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 73 | [[0,0,0,0,0,0,0,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,0,0,0,0,0,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 74 | [[0,0,0,0,0,0,0,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,0,0,0,0,0,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 75 | [[1,1,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,0,0,0,1,],[0,1,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 76 | [[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,0,0,0,0,0,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 77 | [[0,0,0,0,0,0,0,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[0,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 78 | [[0,0,0,0,0,0,0,1,],[1,1,1,1,0,1,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,0,1,1,1,1,],[0,0,0,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 79 | [[0,1,1,1,1,0,1,1,],[0,1,1,1,0,1,1,1,],[0,1,1,0,1,1,1,1,],[0,1,0,0,1,1,1,1,],[0,0,1,1,0,1,1,1,],[0,1,1,1,1,0,1,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 80 | [[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 81 | [[0,1,1,1,1,1,0,1,],[0,0,1,1,1,0,0,1,],[0,1,0,1,0,1,0,1,],[0,1,1,0,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 82 | [[0,1,1,1,1,1,0,1,],[0,0,1,1,1,1,0,1,],[0,1,0,1,1,1,0,1,],[0,1,1,0,1,1,0,1,],[0,1,1,1,0,1,0,1,],[0,1,1,1,1,0,0,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 83 | [[1,1,0,0,0,1,1,1,],[1,0,1,1,1,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,0,1,1,1,0,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 84 | [[0,0,0,0,0,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,0,0,0,0,0,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 85 | [[1,1,0,0,0,1,1,1,],[1,0,1,1,1,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,0,1,0,1,],[1,0,1,1,1,0,1,1,],[1,1,0,0,0,1,0,1,],[1,1,1,1,1,1,1,1,],], 86 | [[0,0,0,0,0,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,0,0,0,0,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 87 | [[1,0,0,0,0,1,1,1,],[0,1,1,1,1,0,1,1,],[0,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 88 | [[0,0,0,0,0,0,0,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 89 | [[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 90 | [[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,0,1,1,1,0,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 91 | [[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[0,1,1,0,1,1,0,1,],[0,1,0,1,0,1,0,1,],[0,0,1,1,1,0,0,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 92 | [[0,1,1,1,1,1,0,1,],[1,0,1,1,1,0,1,1,],[1,1,0,1,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,0,1,0,1,1,1,],[1,0,1,1,1,0,1,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 93 | [[0,1,1,1,1,1,0,1,],[1,0,1,1,1,0,1,1,],[1,1,0,1,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 94 | [[0,0,0,0,0,0,0,1,],[1,1,1,1,1,0,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,0,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[0,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 95 | [[1,1,0,0,0,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 96 | [[1,1,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,1,0,1,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,1,1,0,1,1,],[1,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 97 | [[1,1,0,0,0,0,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,0,0,1,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 98 | [[1,1,1,0,1,1,1,1,],[1,1,0,1,0,1,1,1,],[1,1,0,1,0,1,1,1,],[1,0,1,1,1,0,1,1,],[1,0,1,1,1,0,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 99 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 100 | [[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,0,1,],[1,0,0,1,1,0,0,1,],[1,0,1,0,0,1,0,1,],[1,0,1,0,0,1,0,1,],[1,0,0,1,1,0,0,1,],[1,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 101 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,0,1,1,1,],[1,1,1,1,1,0,1,1,],[1,1,0,0,0,0,1,1,],[1,0,1,1,1,0,1,1,],[1,1,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 102 | [[1,0,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 103 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,0,0,0,1,],[1,0,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,0,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 104 | [[1,1,1,1,1,1,0,1,],[1,1,1,1,1,1,0,1,],[1,1,1,1,1,1,0,1,],[1,1,0,0,0,0,0,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 105 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[1,0,0,0,0,0,0,1,],[1,0,1,1,1,1,1,1,],[1,1,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 106 | [[1,1,1,1,0,0,1,1,],[1,1,1,0,1,1,0,1,],[1,1,1,0,1,1,1,1,],[1,0,0,0,0,0,0,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 107 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,0,0,1,1,],[1,0,1,1,1,0,1,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,0,1,1,],[1,0,0,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 108 | [[1,0,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 109 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 110 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,0,0,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 111 | [[1,0,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,0,1,1,1,0,1,1,],[1,0,1,0,0,1,1,1,],[1,0,0,1,1,1,1,1,],[1,0,1,0,0,1,1,1,],[1,0,1,1,1,0,1,1,],[1,1,1,1,1,1,1,1,],], 112 | [[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 113 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[0,0,0,1,0,0,1,1,],[0,1,1,0,1,1,0,1,],[0,1,1,0,1,1,0,1,],[0,1,1,0,1,1,0,1,],[0,1,1,0,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 114 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,1,1,1,1,1,1,],], 115 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 116 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,0,0,0,0,1,1,],[1,0,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],], 117 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,0,0,1,1,],[1,0,1,1,1,0,1,1,],[1,0,1,1,1,0,1,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,0,1,1,],[1,1,1,1,1,0,0,1,],], 118 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,1,1,0,0,0,1,],[1,0,1,0,1,1,1,1,],[1,0,0,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 119 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,0,0,0,0,0,1,],[1,0,1,1,1,1,1,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,1,0,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 120 | [[1,1,1,1,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 121 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,0,0,0,0,0,1,],[1,1,1,1,1,1,1,1,],], 122 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,0,1,1,0,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 123 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[0,1,1,1,1,1,0,1,],[0,1,1,0,1,1,0,1,],[0,1,1,0,1,1,0,1,],[0,1,0,1,0,1,0,1,],[1,0,1,1,1,0,1,1,],[1,1,1,1,1,1,1,1,],], 124 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,1,1,1,0,1,1,],[1,1,0,1,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,0,1,0,1,1,1,],[1,0,1,1,1,0,1,1,],[1,1,1,1,1,1,1,1,],], 125 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,1,1,1,1,0,1,],[1,0,1,1,1,1,0,1,],[1,1,0,0,0,0,0,1,],[1,1,1,1,1,1,0,1,],[1,1,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 126 | [[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,0,1,1,1,1,1,],[1,0,0,0,0,0,1,1,],[1,1,1,1,1,1,1,1,],], 127 | [[1,1,1,0,0,1,1,1,],[1,1,0,1,1,1,1,1,],[1,1,0,1,1,1,1,1,],[1,0,1,1,1,1,1,1,],[1,1,0,1,1,1,1,1,],[1,1,0,1,1,1,1,1,],[1,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],], 128 | [[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 129 | [[1,1,0,0,1,1,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,1,1,0,1,1,],[1,1,1,1,0,1,1,1,],[1,1,1,1,0,1,1,1,],[1,1,0,0,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 130 | [[1,1,1,1,1,1,1,1,],[1,0,0,1,1,0,1,1,],[0,1,1,0,0,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],[1,1,1,1,1,1,1,1,],], 131 | [[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],[0,1,1,1,1,1,1,1,],], 132 | ]); 133 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | oK repl 4 | 98 | 99 | 100 |
101 |
102 |
103 |
104 | 107 | 108 | 109 | 110 | 111 | 112 | 408 | 409 | -------------------------------------------------------------------------------- /mobile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | oK Mobile 4 | 5 | 6 | 7 | 8 | 9 | 153 | 154 | 155 |
156 |
157 | 158 |
159 |
160 |
161 | 162 | 163 | 164 | 799 | -------------------------------------------------------------------------------- /mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnEarnest/ok/5c47dc358aac5dfd3c8a50c61cae3d081ccee5f6/mobile.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { "name": "ok" 2 | , "version": "0.0.0" 3 | , "license" : "MIT" 4 | , "description": "An open-source interpreter for the K5 programming language" 5 | , "scripts": { "start": "node repl.js" } 6 | , "main": "oK.js" 7 | } -------------------------------------------------------------------------------- /repl.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var ok = require('./oK'); 3 | var fs = require('fs'); 4 | var os = require('os'); 5 | var path = require('path'); 6 | var readline = require('readline'); 7 | var conv = require('./convert'); 8 | help = `oK has atom, list (2;\`c), dict \`a\`b!(2;\`c) and func {[x;y]x+y} 9 | 20 primitives/verbs, 6 operators/adverbs and 3 system functions 10 | 11 | Verb (unary) Adverb Noun (null) 12 | : gets ' each name \`a\`b \` 13 | + plus flip / over|join char "ab" " " 14 | - minus negate \\ scan|split num 2 .3 0N(nan) 0w(inf) 15 | * times first ': eachprior hex 0x2a2b 16 | % divide sqrt /: eachright bool 01000b 17 | ! mod|map enum|key \\: eachleft 18 | & min|and where 19 | | max|or reverse System list (2;3.4;\`ab) 20 | < less asc 0: file r/w dict \`a\`b!(2;\`c) 21 | > more desc 1: json r/w view f::32+1.8*c 22 | = equal group 5: printable form func {[c]32+1.8*c} 23 | ~ match not 24 | , concat enlist 25 | ^ fill|out null \\t x time 26 | # take|rsh count \\\\ exit 27 | _ drop|cut floor 28 | $ cast|sum string $[c;t;f] COND 29 | ? find|rnd distinct ?[x;I;[f;]y] insert 30 | @ at type @[x;i;[f;]y] amend 31 | . dot eval|val .[x;i;[f;]y] dmend 32 | 33 | A manual of the oK language is available with more details: 34 | https://github.com/JohnEarnest/ok/blob/gh-pages/docs/Manual.md 35 | A more general introduction to array programming is also provided: 36 | https://github.com/JohnEarnest/ok/blob/gh-pages/docs/Programming.md 37 | ` 38 | 39 | // register I/O hooks 40 | function str(x) { // convert a k string or symbol to a js string 41 | var s = conv.tojs(x); 42 | if (typeof s !== 'string') { throw Error('ERROR: type'); } 43 | return s; 44 | } 45 | function readp(dt, x) { 46 | var f = str(x); 47 | var tojs; 48 | if (f) { 49 | f = path.resolve(process.cwd(), f); 50 | if (dt==0) { 51 | return conv.tok(fs.statSync(f).isDirectory() ? fs.readdirSync(f) : fs.readFileSync(f, 'utf8').replace(/\r?\n$/, '').split(/\r?\n/)); 52 | } else if (dt==1) { 53 | if (!fs.statSync(f).isDirectory()) { tojs = fs.readFileSync(f, 'utf8'); } 54 | else { throw Error("ERROR: Path '"+f+"' is a directory"); } 55 | } 56 | } else if (rl) { 57 | throw Error('ERROR: cannot read from stdin while in REPL'); 58 | } else { 59 | var b = Buffer(128), b0, n = 0; 60 | while (fs.readSync(process.stdin.fd, b, n, 1) && b[n] !== 10) { 61 | n++; 62 | if (n === b.length) { b0 = b; b = Buffer(2 * n); b0.copy(b, 0, 0, n); b0 = null; } // resize buffer when full 63 | } 64 | if (dt==0) { return conv.tok(b.toString('utf8', 0, n)); } 65 | else if (dt==1) { tojs = b.toString('utf8', 0, n); } 66 | } 67 | if (tojs) { 68 | try { return conv.tok(JSON.parse(tojs)); } 69 | catch (err) { throw Error('JSON parsing error: ' + err.message); } 70 | } 71 | } 72 | function writep(dt, x, y) { 73 | var s = conv.tojs(y); 74 | if (dt==0) { 75 | if (Array.isArray(s)) { s = s.join('\n') + '\n'; } 76 | if (typeof s !== 'string') { throw Error('ERROR: type'); } 77 | } else if (dt==1) { 78 | s = JSON.stringify(s); 79 | } 80 | var f = str(x); 81 | if (f) { fs.writeFileSync(path.resolve(process.cwd(), f), s); } 82 | else { fs.writeSync(process.stdout.fd, s); } 83 | return y; 84 | } 85 | for (var i = 0; i < 2; i++) { ok.setIO('0:', i, function(x) { return readp(0,x); }); } 86 | for (var i = 0; i < 2; i++) { ok.setIO('1:', i, function(x) { return readp(1,x); }); } 87 | for (var i = 0; i < 2; i++) { ok.setIO('5:', 1, function(x) { return conv.tok(ok.format(x)); }); } 88 | for (var i = 2; i < 6; i++) { ok.setIO('0:', i, function(x,y) { return writep(0,x,y); }); } 89 | for (var i = 2; i < 6; i++) { ok.setIO('1:', i, function(x,y) { return writep(1,x,y); }); } 90 | 91 | var env = ok.baseEnv(); 92 | 93 | // run user prelude file if exists 94 | try { 95 | var preludeFile = os.homedir() + "/.config/okrc.k" 96 | var program = fs.readFileSync(preludeFile, 'utf8'); 97 | ok.run(ok.parse(program), env) 98 | } catch (err) { 99 | if (err.code != 'ENOENT') throw err 100 | } 101 | 102 | // process filename.k as a command-line arg 103 | if (process.argv.length > 2) { 104 | var program = fs.readFileSync(process.argv[2], 'utf8'); 105 | env.put('x', true, conv.tok(process.argv.slice(3))) 106 | process.stdout.write(ok.format(ok.run(ok.parse(program), env)) + '\n'); 107 | process.exit(0); 108 | } 109 | 110 | // actual REPL 111 | process.stdout.write('oK v' + ok.version + ' (inspired by K5: http://kparc.com/k.txt; \\h for help)\n'); 112 | var rl = readline.createInterface({ 113 | input: process.stdin, 114 | output: process.stdout, 115 | completer: function (line) { 116 | var m = /[a-z][a-z\d]*$/i.exec(line); 117 | var prefix = m ? m[0] : ''; 118 | var names = []; 119 | for (var e = env; e; e = e.p) { // iterate over ancestor environments 120 | for (var name in e.d) { 121 | if (name.slice(0, prefix.length) === prefix && names.indexOf(name) < 0) { 122 | names.push(name); 123 | } 124 | } 125 | } 126 | return [names, prefix]; 127 | } 128 | }); 129 | rl.on('line', function (line) { 130 | if (line === '\\\\') { process.exit(0); } 131 | var showtime = false; 132 | var showhelp = false; 133 | if (line.lastIndexOf("\\t") == 0) { 134 | line = line.slice(2); 135 | showtime = true; 136 | } else if (line.lastIndexOf("\\h") == 0) { 137 | showhelp = true; 138 | } 139 | try { 140 | if (line.trim()) { 141 | if (!showhelp) { 142 | var starttime = new Date().getTime(); 143 | var output = ok.format(ok.run(ok.parse(line), env)) + '\n'; 144 | if (showtime) { 145 | var endtime = new Date().getTime(); 146 | output += "completed in "+(endtime-starttime)+"ms.\n"; 147 | } 148 | } else { 149 | output = help; 150 | } 151 | process.stdout.write(output); 152 | } 153 | } catch (err) { process.stdout.write(err.message + '\n'); } 154 | rl.prompt(); 155 | }); 156 | rl.on('close', function () { process.stdout.write('\n'); process.exit(0); }); 157 | rl.setPrompt(' '); rl.prompt(); 158 | --------------------------------------------------------------------------------