├── examples ├── quine.alice ├── hw.alice ├── hw-ord.alice ├── is-prime.alice ├── fibonacci-loop.alice └── fizzbuzz.alice ├── .gitignore ├── alice.sublime-project ├── interpreter.rb ├── point2d.rb ├── LICENSE ├── alice.rb ├── direction.rb ├── state.rb ├── mode.rb └── README.md /examples/quine.alice: -------------------------------------------------------------------------------- 1 | "!<@O&9h. -------------------------------------------------------------------------------- /examples/hw.alice: -------------------------------------------------------------------------------- 1 | "!dlroW ,olleH"d&O`@ -------------------------------------------------------------------------------- /examples/hw-ord.alice: -------------------------------------------------------------------------------- 1 | /OH!lloo / 2 | @""edlr,W\ -------------------------------------------------------------------------------- /examples/is-prime.alice: -------------------------------------------------------------------------------- 1 | / \cdtn/ o @ 2 | i 3 | -------------------------------------------------------------------------------- /examples/fibonacci-loop.alice: -------------------------------------------------------------------------------- 1 | 1./ \!?+?~# 2 | O -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | mycode 2 | 3 | *.sublime-workspace 4 | 5 | *.nb -------------------------------------------------------------------------------- /alice.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "path": "." 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /examples/fizzbuzz.alice: -------------------------------------------------------------------------------- 1 | h0!.3%=e!"Fizz/ o\>.5%="/?uoz o\>.'c-&@aO 2 | > \" /^ >.\B$z " /^ -------------------------------------------------------------------------------- /interpreter.rb: -------------------------------------------------------------------------------- 1 | #!ruby --encoding utf-8:utf-8 2 | # coding: utf-8 3 | 4 | require_relative 'alice' 5 | 6 | if ARGV.size == 0 7 | puts "Usage: ruby interpreter.rb source.alice [args ...]" 8 | else 9 | source = File.read(ARGV.shift) 10 | 11 | alice = Alice.new(source) 12 | 13 | begin 14 | alice.run 15 | rescue => e 16 | alice.state.print_debug_info 17 | $stderr.puts e.message 18 | $stderr.puts e.backtrace 19 | end 20 | end -------------------------------------------------------------------------------- /point2d.rb: -------------------------------------------------------------------------------- 1 | class Point2D 2 | attr_accessor :x, :y 3 | 4 | def initialize(x, y) 5 | @x = x 6 | @y = y 7 | end 8 | 9 | def self.from_string(string) 10 | coords = string.split.map(&:to_i) 11 | Point2D.new(coords[0], coords[1]) 12 | end 13 | 14 | def +(other) 15 | if other.is_a?(Point2D) 16 | return Point2D.new(@x+other.x, @y+other.y) 17 | end 18 | end 19 | 20 | def -(other) 21 | if other.is_a?(Point2D) 22 | return Point2D.new(@x-other.x, @y-other.y) 23 | end 24 | end 25 | 26 | def *(other) 27 | if other.is_a?(Numeric) 28 | return Point2D.new(@x*other, @y*other) 29 | end 30 | end 31 | 32 | def /(other) 33 | if other.is_a?(Numeric) 34 | return Point2D.new(@x/other, @y/other) 35 | end 36 | end 37 | 38 | def coerce(other) 39 | return self, other 40 | end 41 | 42 | def to_s 43 | "#{@x} #{@y}" 44 | end 45 | 46 | def pretty 47 | "(%d,%d)" % [@x, @y] 48 | end 49 | end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Martin Ender 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /alice.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | Encoding.default_internal = Encoding::UTF_8 4 | Encoding.default_external = Encoding::UTF_8 5 | 6 | require_relative 'state' 7 | 8 | # Add stable sorting methods to Enumerable 9 | module Enumerable 10 | def stable_sort 11 | sort_by.with_index { |x, idx| [x, idx] } 12 | end 13 | 14 | def stable_sort_by 15 | sort_by.with_index { |x, idx| [yield(x), idx] } 16 | end 17 | end 18 | 19 | # Add convenience method for .chr(Encoding::UTF_8) 20 | class Integer 21 | def chr_utf_8 22 | chr(Encoding::UTF_8) 23 | end 24 | end 25 | 26 | class Alice 27 | attr_accessor :state 28 | 29 | class ProgramError < Exception; end 30 | 31 | 32 | def self.run(src, in_str=$stdin, out_str=$stdout, args=ARGV, max_ticks=-1) 33 | new(src, in_str, out_str, args, max_ticks).run 34 | end 35 | 36 | def initialize(src, in_str=$stdin, out_str=$stdout, args=ARGV, max_ticks=-1) 37 | @state = State.new(src, in_str, out_str, args, max_ticks) 38 | end 39 | 40 | def run 41 | ticks_exceeded = false 42 | 43 | loop do 44 | next while !@state.mode.move 45 | 46 | cell = @state.cell 47 | processed = false 48 | if @state.string_mode 49 | case cell 50 | when "'".ord 51 | @state.mode.raw_move 52 | @state.current_string << @state.cell 53 | @state.ip -= @state.dir.vec 54 | processed = true 55 | when '"'.ord 56 | @state.string_mode = false 57 | else 58 | @state.current_string << cell 59 | processed = true 60 | end 61 | elsif cell == '"'.ord 62 | @state.string_mode = true 63 | @state.current_string = [] 64 | processed = true 65 | end 66 | 67 | if !processed 68 | iterator = @state.get_iterator 69 | case iterator 70 | when Integer 71 | iterator.times { @state.mode.process cell.chr_utf_8 } 72 | when String 73 | iterator.each_char do |c| 74 | @state.push c 75 | @state.mode.process cell.chr_utf_8 76 | end 77 | end 78 | end 79 | 80 | @state.tick += 1 81 | ticks_exceeded = @state.max_ticks > -1 && @state.tick >= @state.max_ticks 82 | break if @state.done || ticks_exceeded 83 | end 84 | 85 | ticks_exceeded 86 | end 87 | 88 | private 89 | 90 | def error msg 91 | raise msg 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /direction.rb: -------------------------------------------------------------------------------- 1 | require_relative 'point2d' 2 | 3 | class North 4 | def right() East.new end 5 | def left() West.new end 6 | def reverse() South.new end 7 | def vec() Point2D.new(0,-1) end 8 | 9 | def reflect(mirror) 10 | case mirror 11 | when '/'; SouthWest.new 12 | when '\\'; SouthEast.new 13 | when '_'; South.new 14 | when '|'; North.new 15 | end 16 | end 17 | 18 | def ==(other) other.is_a?(North) end 19 | def coerce(other) return self, other end 20 | end 21 | 22 | class NorthEast 23 | def right() SouthEast.new end 24 | def left() NorthWest.new end 25 | def reverse() SouthWest.new end 26 | def vec() Point2D.new(1,-1) end 27 | 28 | def reflect(mirror) 29 | case mirror 30 | when '/'; South.new 31 | when '\\'; East.new 32 | when '_'; SouthEast.new 33 | when '|'; NorthWest.new 34 | end 35 | end 36 | 37 | def ==(other) other.is_a?(NorthEast) end 38 | def coerce(other) return self, other end 39 | end 40 | 41 | class East 42 | def right() South.new end 43 | def left() North.new end 44 | def reverse() West.new end 45 | def vec() Point2D.new(1,0) end 46 | 47 | def reflect(mirror) 48 | case mirror 49 | when '/'; SouthEast.new 50 | when '\\'; NorthEast.new 51 | when '_'; East.new 52 | when '|'; West.new 53 | end 54 | end 55 | 56 | def ==(other) other.is_a?(East) end 57 | def coerce(other) return self, other end 58 | end 59 | 60 | class SouthEast 61 | def right() SouthWest.new end 62 | def left() NorthEast.new end 63 | def reverse() NorthWest.new end 64 | def vec() Point2D.new(1,1) end 65 | 66 | def reflect(mirror) 67 | case mirror 68 | when '/'; East.new 69 | when '\\'; North.new 70 | when '_'; NorthEast.new 71 | when '|'; SouthWest.new 72 | end 73 | end 74 | 75 | def ==(other) other.is_a?(SouthEast) end 76 | def coerce(other) return self, other end 77 | end 78 | 79 | class South 80 | def right() West.new end 81 | def left() East.new end 82 | def reverse() North.new end 83 | def vec() Point2D.new(0,1) end 84 | 85 | def reflect(mirror) 86 | case mirror 87 | when '/'; NorthEast.new 88 | when '\\'; NorthWest.new 89 | when '_'; North.new 90 | when '|'; South.new 91 | end 92 | end 93 | 94 | def ==(other) other.is_a?(South) end 95 | def coerce(other) return self, other end 96 | end 97 | 98 | class SouthWest 99 | def right() NorthWest.new end 100 | def left() SouthEast.new end 101 | def reverse() NorthEast.new end 102 | def vec() Point2D.new(-1,1) end 103 | 104 | def reflect(mirror) 105 | case mirror 106 | when '/'; North.new 107 | when '\\'; West.new 108 | when '_'; NorthWest.new 109 | when '|'; SouthEast.new 110 | end 111 | end 112 | 113 | def ==(other) other.is_a?(SouthWest) end 114 | def coerce(other) return self, other end 115 | end 116 | 117 | class West 118 | def right() North.new end 119 | def left() South.new end 120 | def reverse() East.new end 121 | def vec() Point2D.new(-1,0) end 122 | 123 | def reflect(mirror) 124 | case mirror 125 | when '/'; NorthWest.new 126 | when '\\'; SouthWest.new 127 | when '_'; West.new 128 | when '|'; East.new 129 | end 130 | end 131 | 132 | def ==(other) other.is_a?(West) end 133 | def coerce(other) return self, other end 134 | end 135 | 136 | class NorthWest 137 | def right() NorthEast.new end 138 | def left() SouthWest.new end 139 | def reverse() SouthEast.new end 140 | def vec() Point2D.new(-1,-1) end 141 | 142 | def reflect(mirror) 143 | case mirror 144 | when '/'; West.new 145 | when '\\'; South.new 146 | when '_'; SouthWest.new 147 | when '|'; NorthEast.new 148 | end 149 | end 150 | 151 | def ==(other) other.is_a?(NorthWest) end 152 | def coerce(other) return self, other end 153 | end 154 | -------------------------------------------------------------------------------- /state.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | require_relative 'mode' 4 | require_relative 'point2d' 5 | require_relative 'direction' 6 | 7 | class State 8 | # I'm sorry. 9 | attr_accessor :in_str, :out_str, :args, :max_ticks, 10 | :grid, :height, :width, 11 | :ip, :dir, :storage_offset, 12 | :stack, :tape, :rp, :mp, :string_mode, :current_string, 13 | :tick, :done, 14 | :mode 15 | 16 | def initialize(src, in_str=$stdin, out_str=$stdout, args=ARGV, max_ticks=-1) 17 | @in_str = in_str 18 | @out_str = out_str 19 | @out_str.binmode # Put the output stream in binary mode so that 20 | # we can write non-UTF-8 bytes. 21 | @args = args 22 | 23 | @max_ticks = max_ticks 24 | 25 | @grid = parse(src) 26 | @height = @grid.size 27 | @width = @height == 0 ? 0 : @grid[0].size 28 | 29 | @ip = Point2D.new(-1, 0) # Instruction pointer 30 | @dir = East.new 31 | @storage_offset = Point2D.new(0, 0) # Will be used when source modification grows the 32 | # to the West or to the North. 33 | @stack = [] 34 | @tape = Hash.new(-1) 35 | @mp = 0 # Memory pointer 36 | @rp = 0 # Register pointer 37 | @string_mode = false 38 | @current_string = [] 39 | @return_stack = [] 40 | @iterator_queue = [] 41 | 42 | @tick = 0 43 | @done = false 44 | 45 | @cardinal = Cardinal.new(self) 46 | @ordinal = Ordinal.new(self) 47 | 48 | set_cardinal 49 | end 50 | 51 | def x 52 | @ip.x 53 | end 54 | 55 | def y 56 | @ip.y 57 | end 58 | 59 | def jump x, y 60 | @ip.x = x 61 | @ip.y = y 62 | end 63 | 64 | def cell(coords=@ip) 65 | offset = coords + @storage_offset 66 | line = offset.y < 0 ? [] : @grid[offset.y] || [] 67 | offset.x < 0 ? -1 : line[offset.x] || -1 68 | end 69 | 70 | def put_cell(coords, value) 71 | offset = coords + @storage_offset 72 | 73 | # Grow grid if necessary 74 | if offset.x >= @width 75 | @width = offset.x+1 76 | @grid.each{|l| l.fill(-1, l.length...@width)} 77 | end 78 | 79 | if offset.x < 0 80 | @width -= offset.x 81 | @storage_offset.x -= offset.x 82 | @grid.map{|l| l.unshift(*[-1]*(-offset.x))} 83 | offset.x = 0 84 | end 85 | 86 | if offset.y >= @height 87 | @height = offset.y+1 88 | while @grid.size < height 89 | @grid << [-1]*@width 90 | end 91 | end 92 | 93 | if offset.y < 0 94 | @height -= offset.y 95 | @storage_offset.y -= offset.y 96 | while @grid.size < height 97 | @grid.unshift([-1]*@width) 98 | end 99 | offset.y = 0 100 | end 101 | 102 | @grid[offset.y][offset.x] = value 103 | 104 | # Shrink the grid if possible 105 | if value == 0 && on_boundary(coords) 106 | while @height > 0 && @grid[0]-[-1] == [] 107 | @grid.shift 108 | @height -= 1 109 | end 110 | 111 | while @height > 0 && @grid[-1]-[-1] == [] 112 | @grid.pop 113 | @height -= 1 114 | end 115 | 116 | while @width > 0 && @grid.transpose[0]-[-1] == [] 117 | @grid.map(&:shift) 118 | @width -= 1 119 | end 120 | 121 | while @width > 0 && @grid.transpose[-1]-[-1] == [] 122 | @grid.map(&:pop) 123 | @width -= 1 124 | end 125 | end 126 | end 127 | 128 | def min_x 129 | -@storage_offset.x 130 | end 131 | 132 | def min_y 133 | -@storage_offset.y 134 | end 135 | 136 | def max_x 137 | @width - @storage_offset.x - 1 138 | end 139 | 140 | def max_y 141 | @height - @storage_offset.y - 1 142 | end 143 | 144 | def on_boundary(coords=@ip) 145 | coords.x == min_x || coords.y == min_y || coords.x == max_x || coords.y == max_y 146 | end 147 | 148 | def wrap 149 | @ip += @storage_offset 150 | case @dir 151 | when East 152 | @ip.x = 0 if @ip.x >= @width 153 | when West 154 | @ip.x = @width-1 if @ip.x < 0 155 | when South 156 | @ip.y = 0 if @ip.y >= @height 157 | when North 158 | @ip.y = @height-1 if @ip.y < 0 159 | end 160 | @ip -= @storage_offset 161 | end 162 | 163 | def set_cardinal 164 | @mode = @cardinal 165 | @other_mode = @ordinal 166 | end 167 | 168 | def set_ordinal 169 | @mode = @ordinal 170 | @other_mode = @cardinal 171 | end 172 | 173 | def toggle_mode 174 | @mode, @other_mode = @other_mode, @mode 175 | end 176 | 177 | def push val 178 | @stack << val 179 | end 180 | 181 | def pop 182 | @stack.pop 183 | end 184 | 185 | def push_return(coords=@ip) 186 | @return_stack.push([coords.x, coords.y]) 187 | end 188 | 189 | def pop_return 190 | @return_stack.pop || [@ip.x, @ip.y] 191 | end 192 | 193 | def peek_return 194 | @return_stack[-1] || [@ip.x, @ip.y] 195 | end 196 | 197 | def get_iterator 198 | @iterator_queue.shift || 1 199 | end 200 | 201 | def add_iterator iter 202 | @iterator_queue << iter 203 | end 204 | 205 | def skip_next 206 | @iterator_queue.unshift(0) 207 | end 208 | 209 | def read_register 210 | chars = [] 211 | i = @rp 212 | while is_char?(@tape[i]) 213 | chars << @tape[i] 214 | i += 1 215 | end 216 | chars.map(&:chr_utf_8).join 217 | end 218 | 219 | def print_debug_info 220 | $stderr.puts "Mode: #{@mode.class}" 221 | print_grid 222 | print_iterators 223 | print_stack 224 | print_tape 225 | print_register 226 | print_args 227 | print_tick 228 | end 229 | 230 | def print_grid 231 | $stderr.puts 'Grid:' 232 | $stderr.puts ' '*(@ip.x+@storage_offset.x)+'v' 233 | @grid.each_with_index do |line, i| 234 | line.each {|c| $stderr << (is_char?(c) && (c == 10 || c >= 32) ? c : 32).chr_utf_8} 235 | $stderr << ' <' if i == @ip.y + @storage_offset.y 236 | $stderr.puts 237 | end 238 | $stderr.puts 239 | $stderr.puts "Top left coordinate: #{(@storage_offset*-1).pretty}" 240 | $stderr.puts "IP: #{@ip.pretty}" 241 | $stderr.puts "Direction: #{@dir.class}" 242 | $stderr.puts "Return address stack: ... (0,0)#{@return_stack.map{|p|' ('+p[0].to_s+','+p[1].to_s+')'}.join}" 243 | $stderr.puts 244 | end 245 | 246 | def print_iterators 247 | $stderr.puts 'Iterators:' 248 | $stderr.puts "<< #{@iterator_queue.empty? ? '(1)' : @iterator_queue.map(&:inspect).join(' ')} <<" 249 | $stderr.puts 250 | end 251 | 252 | def print_tape 253 | $stderr.puts 'Tape:' 254 | min, max = [@mp, @rp, *@tape.keys].minmax 255 | width = 0 256 | rp_str = "OTH:" 257 | tape_str = " ..." 258 | mp_str = "CTH:" 259 | (min-1 .. max+1).map do |i| 260 | s = @tape[i].to_s 261 | tape_str << ' ' << s 262 | rp_str << ' ' << (i == @rp ? 'v'*s.size + " (#{i})" : ' '*s.size) 263 | mp_str << ' ' << (i == @mp ? '^'*s.size + " (#{i})" : ' '*s.size) 264 | end 265 | tape_str << ' ...' 266 | $stderr.puts rp_str 267 | $stderr.puts tape_str 268 | $stderr.puts mp_str 269 | $stderr.puts 270 | end 271 | 272 | def print_stack 273 | $stderr.puts 'Stack:' 274 | $stderr.puts "[...#{@stack.map{|e|' '+e.inspect}.join}]" 275 | $stderr.puts 276 | end 277 | 278 | def print_register 279 | $stderr.puts 'Register:' 280 | $stderr.puts read_register 281 | $stderr.puts 282 | end 283 | 284 | def print_args 285 | $stderr.puts 'Remaining arguments:' 286 | $stderr.puts @args.inspect 287 | $stderr.puts 288 | end 289 | 290 | def print_tick 291 | $stderr.puts "Tick: #{@tick}" 292 | $stderr.puts 293 | end 294 | 295 | private 296 | 297 | def is_char? val 298 | val && (val >= 0 && val <= 0xD7FF || val >= 0xE000 && val <= 0x10FFFF) 299 | end 300 | 301 | def parse(src) 302 | lines = src.split($/, -1) 303 | 304 | grid = lines.map{|l| l.chars.map(&:ord)} 305 | 306 | width = [*grid.map(&:size), 1].max 307 | 308 | grid.each{|l| l.fill(32, l.length...width)} 309 | end 310 | end 311 | -------------------------------------------------------------------------------- /mode.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | require_relative 'point2d' 4 | require_relative 'direction' 5 | 6 | require 'prime' 7 | require 'date' 8 | 9 | class Mode 10 | # List of operators which should not be ignored while in string mode. 11 | STRING_CMDS = "\"'\\/_|" 12 | 13 | def initialize(state) 14 | @state = state 15 | end 16 | 17 | def is_char? val 18 | val && (val >= 0 && val <= 0xD7FF || val >= 0xE000 && val <= 0x10FFFF) 19 | end 20 | 21 | def process 22 | raise NotImplementedError 23 | end 24 | 25 | # Returns true when the resulting cell is a command. 26 | def move 27 | raw_move if @state.cell == "'".ord 28 | raw_move 29 | 30 | cell = @state.cell 31 | case cell 32 | when '/'.ord, '\\'.ord 33 | @state.dir = @state.dir.reflect cell.chr_utf_8 34 | @state.toggle_mode 35 | return false 36 | when '_'.ord, '|'.ord 37 | @state.dir = @state.dir.reflect cell.chr_utf_8 38 | return false 39 | end 40 | 41 | return true if @state.string_mode 42 | 43 | @state.print_debug_info if cell == '`'.ord 44 | 45 | is_char?(cell) && self.class::OPERATORS.has_key?(cell.chr_utf_8) 46 | end 47 | 48 | # Moves the IP a single cell without regard for mirrors, walls or no-ops. 49 | # Does respect grid boundaries. 50 | def raw_move 51 | raise NotImplementedError 52 | end 53 | 54 | def push val 55 | @state.push val 56 | end 57 | 58 | def pop 59 | raise NotImplementedError 60 | end 61 | 62 | def push_return 63 | @state.push_return 64 | end 65 | 66 | def pop_return 67 | @state.pop_return 68 | end 69 | 70 | def peek_return 71 | @state.peek_return 72 | end 73 | 74 | def peek 75 | val = pop 76 | push val 77 | val 78 | end 79 | end 80 | 81 | class Cardinal < Mode 82 | OPERATORS = { 83 | '@' => :terminate, 84 | 85 | '<' => :move_west, 86 | '>' => :move_east, 87 | '^' => :move_north, 88 | 'v' => :move_south, 89 | 90 | '{' => :turn_left, 91 | '}' => :turn_right, 92 | 93 | '#' => :trampoline, 94 | '$' => :cond_trampoline, 95 | '=' => :cond_sign, 96 | '&' => :repeat_iterator, 97 | 98 | '~' => :swap, 99 | '.' => :dup, 100 | ';' => :discard, 101 | ',' => :rotate_stack, 102 | 103 | '0' => :digit, '1' => :digit, '2' => :digit, '3' => :digit, '4' => :digit, '5' => :digit, '6' => :digit, '7' => :digit, '8' => :digit, '9' => :digit, 104 | '+' => :add, 105 | '-' => :sub, 106 | '*' => :mul, 107 | ':' => :div, 108 | '%' => :mod, 109 | 110 | '!' => :store_tape, 111 | '?' => :load_tape, 112 | '[' => :mp_left, 113 | ']' => :mp_right, 114 | '(' => :search_left, 115 | ')' => :search_right, 116 | 117 | '"' => :leave_string_mode, 118 | "'" => :escape, 119 | 120 | 'I' => :input, 121 | 'O' => :output, 122 | 'i' => :raw_input, 123 | 'o' => :raw_output, 124 | 125 | 'A' => :bitand, 126 | 'B' => :divisors, 127 | 'C' => :binomial, 128 | 'D' => :deduplicate, 129 | 'E' => :power, 130 | 'F' => :divides, 131 | 'G' => :gcd, 132 | 'H' => :abs, 133 | 'J' => :jump_raw, 134 | 'K' => :return_raw, 135 | 'L' => :lcm, 136 | 'M' => :argc, 137 | 'N' => :bitnot, 138 | 'P' => :factorial, 139 | 'Q' => :convert, 140 | 'R' => :negate, 141 | 'S' => :replace_divisors, 142 | 'T' => :sleep, 143 | 'U' => :random, 144 | 'V' => :bitor, 145 | 'W' => :discard_return, 146 | 'X' => :bitxor, 147 | 'Y' => :unpack, 148 | 'Z' => :pack, 149 | 150 | 'a' => :const_10, 151 | 'b' => :random_swap, 152 | 'c' => :prime_factors, 153 | 'd' => :stack_depth, 154 | 'e' => :const_m1, 155 | 'f' => :prime_factor_pairs, 156 | 'g' => :get_cell, 157 | 'h' => :inc, 158 | 'j' => :jump, 159 | 'k' => :return, 160 | 'l' => :clear_bits, 161 | 'm' => :floor, 162 | 'n' => :not, 163 | 'p' => :put_cell, 164 | 'q' => :get_mp, 165 | 'r' => :range, 166 | 's' => :sortswap, 167 | 't' => :dec, 168 | 'u' => :set_bits, 169 | 'w' => :push_return, 170 | 'x' => :extract_bit, 171 | 'y' => :bitif, 172 | 'z' => :drop_small_factors, 173 | } 174 | 175 | OPERATORS.default = :nop 176 | 177 | def raw_move 178 | @state.ip += @state.dir.vec 179 | @state.wrap 180 | end 181 | 182 | def pop 183 | val = nil 184 | 185 | loop do 186 | val = @state.pop 187 | if val.is_a?(String) 188 | found = false 189 | val.scan(/(?:\A|(?!\G))-?\d+/) { push $&.to_i; found = true } 190 | next if !found 191 | val = @state.pop 192 | end 193 | 194 | break 195 | end 196 | 197 | val || 0 198 | end 199 | 200 | def process cmd 201 | opcode = OPERATORS[cmd] 202 | 203 | case opcode 204 | when :nop 205 | raise "No-op reached process(). This shouldn't happen." 206 | 207 | when :terminate 208 | @state.done = true 209 | 210 | when :move_east 211 | @state.dir = East.new 212 | when :move_west 213 | @state.dir = West.new 214 | when :move_south 215 | @state.dir = South.new 216 | when :move_north 217 | @state.dir = North.new 218 | when :turn_left 219 | @state.dir = @state.dir.left 220 | when :turn_right 221 | @state.dir = @state.dir.right 222 | when :trampoline 223 | @state.skip_next 224 | when :cond_trampoline 225 | @state.skip_next if pop == 0 226 | when :cond_sign 227 | val = pop 228 | if val < 0 229 | @state.dir = @state.dir.left 230 | elsif val > 0 231 | @state.dir = @state.dir.right 232 | end 233 | when :repeat_iterator 234 | @state.add_iterator pop 235 | 236 | when :jump 237 | push_return 238 | y = pop 239 | x = pop 240 | @state.jump(x,y) 241 | when :return 242 | @state.jump(*pop_return) 243 | when :jump_raw 244 | y = pop 245 | x = pop 246 | @state.jump(x,y) 247 | when :return_raw 248 | @state.jump(*peek_return) 249 | when :push_return 250 | push_return 251 | when :discard_return 252 | pop_return 253 | 254 | when :get_cell 255 | y = pop 256 | x = pop 257 | push @state.cell(Point2D.new(x,y)) 258 | when :put_cell 259 | y = pop 260 | x = pop 261 | v = pop 262 | @state.put_cell(Point2D.new(x,y), v) 263 | 264 | when :store_tape 265 | @state.tape[@state.mp] = pop 266 | when :load_tape 267 | push (@state.tape[@state.mp] || -1) 268 | when :mp_left 269 | @state.mp -= 1 270 | when :mp_right 271 | @state.mp += 1 272 | when :search_left 273 | val = pop 274 | (@state.mp-1).downto([*@state.tape.keys, 0].min-1).each do |i| 275 | if @state.tape[i] == val 276 | @state.mp = i 277 | break 278 | end 279 | end 280 | when :search_right 281 | val = pop 282 | (@state.mp+1..[*@state.tape.keys, 0].max+1).each do |i| 283 | if @state.tape[i] == val 284 | @state.mp = i 285 | break 286 | end 287 | end 288 | when :get_mp 289 | push @state.mp 290 | 291 | when :leave_string_mode 292 | @state.stack += @state.current_string 293 | when :escape 294 | old_ip = @state.ip 295 | raw_move 296 | push @state.cell 297 | @state.ip = old_ip 298 | 299 | when :input 300 | char = @state.in_str.getc 301 | while char && char.scrub('') == '' 302 | char = @state.in_str.getc 303 | end 304 | 305 | push(char ? char.ord : -1) 306 | when :output 307 | # Will throw an error when value isn't a valid code point 308 | val = pop 309 | if is_char?(val) 310 | val.chr_utf_8.unpack('C*').each{|c| @state.out_str.putc c } 311 | end 312 | when :raw_input 313 | push(@state.in_str.getbyte || -1) 314 | when :raw_output 315 | @state.out_str.putc pop 316 | when :argc 317 | push @state.args.size 318 | 319 | when :digit 320 | push cmd.to_i 321 | when :add 322 | push(pop + pop) 323 | when :sub 324 | y = pop 325 | push(pop - y) 326 | when :mul 327 | push(pop * pop) 328 | when :div 329 | y = pop 330 | push(pop / y) 331 | when :mod 332 | y = pop 333 | push(pop % y) 334 | when :inc 335 | push(pop+1) 336 | when :dec 337 | push(pop-1) 338 | when :abs 339 | push(pop.abs) 340 | when :power 341 | y = pop 342 | x = pop 343 | if y < 0 344 | # Compute integer root of the absolute base, preserving sign of base 345 | if x < 0 346 | r = 0 347 | # If I'm ever not lazy I'll replace this with a binary search... 348 | r -= 1 while (-r)**-y < -x 349 | push r 350 | else 351 | r = 0 352 | # If I'm ever not lazy I'll replace this with a binary search... 353 | r += 1 until r**-y > x 354 | push (r-1) 355 | end 356 | else 357 | push x**y 358 | end 359 | when :bitand 360 | push(pop & pop) 361 | when :bitnot 362 | push(~pop) 363 | when :bitor 364 | push(pop | pop) 365 | when :bitxor 366 | push(pop ^ pop) 367 | when :bitif 368 | z = pop 369 | y = pop 370 | x = pop 371 | push(x&y | ~x&z) 372 | when :clear_bits 373 | x = pop 374 | if x > 0 375 | msb = Math.log2(x).floor 376 | elsif x < -1 377 | msb = Math.log2(~x).floor 378 | else 379 | msb = 0 380 | end 381 | push (x & -(2**msb)) 382 | when :set_bits 383 | x = pop 384 | if x > 0 385 | msb = Math.log2(x).floor 386 | elsif x < -1 387 | msb = Math.log2(~x).floor 388 | else 389 | msb = 0 390 | end 391 | push (x | (2**msb-1)) 392 | when :extract_bit 393 | y = pop 394 | x = pop 395 | if y >= 0 396 | push x[y] 397 | else 398 | if x > 0 399 | msb = Math.log2(x).floor 400 | elsif x < -1 401 | msb = Math.log2(~x).floor 402 | else 403 | msb = -1 404 | end 405 | push x[msb+y+1] 406 | end 407 | 408 | when :factorial 409 | val = pop 410 | if val >= 0 411 | push (1..val).reduce(1, :*) 412 | else 413 | push (val..-1).reduce(1, :*) 414 | end 415 | when :binomial 416 | k = pop 417 | n = pop 418 | 419 | k = n-k if n > 0 && k > n/2 420 | 421 | if k < 0 422 | push 0 423 | else 424 | prod = 1 425 | (1..k).each do |i| 426 | prod *= n 427 | prod /= i 428 | n -= 1 429 | end 430 | push prod 431 | end 432 | when :negate 433 | push -pop 434 | when :prime_factors 435 | n = pop 436 | if n == 0 437 | push 0 438 | else 439 | Prime.prime_division(n).each{ |p,n| n.times{ push p } } 440 | end 441 | when :prime_factor_pairs 442 | n = pop 443 | if n == 0 444 | push 0 445 | push 1 446 | else 447 | Prime.prime_division(n).flatten.each{ |x| push x } 448 | end 449 | when :deduplicate 450 | n = pop 451 | if n == 0 452 | push 0 453 | else 454 | push Prime.int_from_prime_division(Prime.prime_division(n).map{ |p,n| [p,1]}) 455 | end 456 | when :divides 457 | y = pop 458 | x = pop 459 | if y != 0 && x % y == 0 460 | push y 461 | else 462 | push 0 463 | end 464 | when :gcd 465 | push (pop.gcd pop) 466 | when :lcm 467 | push (pop.lcm pop) 468 | when :floor 469 | y = pop.abs 470 | x = pop 471 | push (x/y)*y 472 | when :replace_divisors 473 | z = pop 474 | y = pop 475 | x = pop 476 | if x == 0 477 | push 0 478 | elsif y == 1 || y == -1 479 | if z == y 480 | push x 481 | elsif z == 0 482 | push 0 483 | else 484 | loop { next } 485 | end 486 | else 487 | order = 0 488 | while x%y == 0 489 | order += 1 490 | x /= y 491 | end 492 | x *= z**order 493 | push x 494 | end 495 | when :divisors 496 | n = pop 497 | sgn = n <=> 0 498 | n = n.abs 499 | k = 1 500 | small_divs = [] 501 | large_divs = [] 502 | while k*k <= n 503 | if n%k == 0 504 | small_divs << k 505 | large_divs << n/k if k*k != n 506 | end 507 | k += 1 508 | end 509 | (small_divs + large_divs.reverse).each {|k| push k*sgn} 510 | 511 | when :drop_small_factors 512 | k = pop 513 | n = pop 514 | 515 | if n.abs > 1 516 | factors = Prime.prime_division(n.abs) 517 | n_dropped = 0 518 | while !factors.empty? && factors[0][0] <= k.abs 519 | pr, m = factors.shift 520 | n_dropped += m 521 | end 522 | n = Prime.int_from_prime_division(factors) * (n <=> 0) 523 | if k < 0 && n_dropped.odd? 524 | n *= -1 525 | end 526 | end 527 | 528 | push n 529 | 530 | when :pack 531 | y = pop 532 | x = pop 533 | 534 | # Map integers to naturals 535 | sgn = x <=> 0 536 | x = x*sgn*2 + [0, sgn].min 537 | 538 | sgn = y <=> 0 539 | y = y*sgn*2 + [0, sgn].min 540 | 541 | # Map two naturals to one 542 | z = (x+y)*(x+y+1)/2 + y 543 | 544 | # Map the natural back to an integer 545 | z = (-1)**z * ((z+1)/2) 546 | 547 | push z 548 | 549 | when :unpack 550 | z = pop 551 | 552 | # Map the integer to a positive natural 553 | sgn = z <=> 0 554 | z = z*sgn*2 + [0, sgn].min 555 | 556 | # Map the natural to two 557 | y = z 558 | x = 0 559 | while x < y 560 | x += 1 561 | y -= x 562 | end 563 | x -= y 564 | 565 | # Map the naturals back to integers 566 | x = (-1)**x * ((x+1)/2) 567 | y = (-1)**y * ((y+1)/2) 568 | 569 | push x 570 | push y 571 | 572 | when :not 573 | push (pop == 0 ? 1 : 0) 574 | 575 | when :range 576 | val = pop 577 | if val >= 0 578 | 0.upto(val) {|i| push i} 579 | else 580 | (-val).downto(0) {|i| push i} 581 | end 582 | 583 | when :random 584 | val = pop 585 | if val > 0 586 | push rand val 587 | elsif val == 0 588 | push 0 589 | else 590 | push -(rand val) 591 | end 592 | when :random_swap 593 | top = pop 594 | second = pop 595 | top, second = [top, second].shuffle 596 | push second 597 | push top 598 | 599 | when :sortswap 600 | top = pop 601 | second = pop 602 | 603 | top, second = second, top if top < second 604 | 605 | push second 606 | push top 607 | 608 | when :swap 609 | top = pop 610 | second = pop 611 | push top 612 | push second 613 | when :dup 614 | top = pop 615 | push top 616 | push top 617 | when :discard 618 | pop 619 | when :stack_depth 620 | push @state.stack.size 621 | when :rotate_stack 622 | n = pop 623 | if n > 0 624 | push(@state.stack.delete_at(-n-1) || 0) 625 | elsif n < 0 626 | top = @state.stack.pop || 0 # Do this manually to prevent type conversion 627 | @state.stack = [0]*[-n-@state.stack.size, 0].max + @state.stack 628 | @state.stack.insert(n-1, top) 629 | end 630 | when :convert 631 | n = pop 632 | n.times.map{pop}.reverse.each{|v| push v} 633 | when :sleep 634 | sleep [0, pop/1000.0].max 635 | when :const_10 636 | push 10 637 | when :const_m1 638 | push -1 639 | 640 | end 641 | end 642 | end 643 | 644 | class Ordinal < Mode 645 | OPERATORS = { 646 | '@' => :terminate, 647 | 648 | '0' => :digit, '1' => :digit, '2' => :digit, '3' => :digit, '4' => :digit, '5' => :digit, '6' => :digit, '7' => :digit, '8' => :digit, '9' => :digit, 649 | '+' => :superimpose, 650 | '-' => :drop, 651 | '*' => :concat, 652 | ':' => :occurrences, 653 | '%' => :split, 654 | 655 | '<' => :ensure_west, 656 | '>' => :ensure_east, 657 | '^' => :ensure_north, 658 | 'v' => :ensure_south, 659 | 660 | '{' => :turn_left, 661 | '}' => :turn_right, 662 | 663 | '#' => :trampoline, 664 | '$' => :cond_trampoline, 665 | '=' => :cond_cmp, 666 | '&' => :fold_iterator, 667 | 668 | '~' => :swap, 669 | '.' => :dup, 670 | ';' => :discard, 671 | ',' => :permute_stack, 672 | 673 | '!' => :store_register, 674 | '?' => :load_register, 675 | '[' => :register_left, 676 | ']' => :register_right, 677 | '(' => :search_left, 678 | ')' => :search_right, 679 | 680 | '"' => :leave_string_mode, 681 | "'" => :escape, 682 | 683 | 'I' => :input, 684 | 'O' => :output, 685 | 'i' => :raw_input, 686 | 'o' => :raw_output, 687 | 688 | 'A' => :intersection, 689 | 'B' => :substrings, 690 | 'C' => :subsequences, 691 | 'D' => :deduplicate, 692 | 'E' => :riffle, 693 | 'F' => :find, 694 | 'G' => :longest_common_substring, 695 | 'H' => :trim, 696 | 'J' => :jump_raw, 697 | 'K' => :return_raw, 698 | 'L' => :shortest_common_superstring, 699 | 'M' => :argv, 700 | 'N' => :complement, 701 | 'P' => :permutations, 702 | 'Q' => :reverse_stack, 703 | 'R' => :reverse, 704 | 'S' => :replace, 705 | 'T' => :datetime, 706 | 'U' => :random_choice, 707 | 'V' => :union, 708 | 'W' => :discard_return, 709 | 'X' => :symdifference, 710 | 'Y' => :unzip, 711 | 'Z' => :zip, 712 | 713 | 'a' => :const_lf, 714 | 'b' => :shuffle, 715 | 'c' => :characters, 716 | 'd' => :push_joined_stack, 717 | 'e' => :const_empty, 718 | 'f' => :runs, 719 | 'g' => :get_diagonal, 720 | 'h' => :head, 721 | 'j' => :jump, 722 | 'k' => :return, 723 | 'l' => :lower_case, 724 | 'm' => :truncate_to_shorter, 725 | 'u' => :upper_case, 726 | 'n' => :not, 727 | 'p' => :put_diagonal, 728 | 'q' => :join_tape, 729 | 'r' => :expand_ranges, 730 | 's' => :sort, 731 | 't' => :tail, 732 | 'w' => :push_return, 733 | 'x' => :permute, 734 | 'y' => :transliterate, 735 | 'z' => :discard_up_to, 736 | 737 | #'(' => , 738 | #')' => , 739 | 740 | #'!' => , 741 | #'$' => , 742 | #'&' => , 743 | #',' => , 744 | #'.' => , 745 | #';' => , 746 | #'=' => , 747 | #'?' => , 748 | #'`' => , 749 | 750 | #'A' => , 751 | # ... 752 | #'Z' => , 753 | #'a' => , 754 | # ... 755 | #'z' => , 756 | } 757 | 758 | OPERATORS.default = :nop 759 | 760 | def raw_move 761 | if @state.width == 1 || @state.height == 1 762 | return 763 | end 764 | 765 | new_pos = @state.ip + @state.dir.vec + @state.storage_offset 766 | @state.dir = @state.dir.reflect('|') if new_pos.x < 0 || new_pos.x >= @state.width 767 | @state.dir = @state.dir.reflect('_') if new_pos.y < 0 || new_pos.y >= @state.height 768 | 769 | @state.ip += @state.dir.vec 770 | end 771 | 772 | def pop 773 | val = @state.pop 774 | 775 | val ? val.to_s : '' 776 | end 777 | 778 | def scan_source label 779 | ip_dir = @state.dir 780 | grid = @state.grid 781 | while !ip_dir.is_a? NorthEast 782 | grid = grid.transpose.reverse 783 | ip_dir = ip_dir.left 784 | end 785 | 786 | height = grid.size 787 | width = height == 0 ? 0 : grid[0].size 788 | 789 | positions = [] 790 | 791 | (0..width+height-2).map do |d| 792 | min_x = [0,d-height+1].max 793 | max_x = [width-1,d].min 794 | line = (min_x..max_x).map do |x| 795 | y = d - x 796 | grid[y][x].chr_utf_8 797 | end.join 798 | 799 | line.scan(/(?=#{Regexp.escape(label)})/) do 800 | x = min_x + $`.size + label.size - 1 801 | y = d-x 802 | positions << [x,y] 803 | end 804 | end 805 | 806 | ip_dir = @state.dir 807 | while !ip_dir.is_a? NorthEast 808 | ip_dir = ip_dir.left 809 | positions.map! {|x, y| [grid.size - y - 1, x]} 810 | grid = grid.reverse.transpose 811 | end 812 | 813 | positions 814 | end 815 | 816 | def process cmd 817 | opcode = OPERATORS[cmd] 818 | 819 | case opcode 820 | when :nop 821 | raise "No-op reached process(). This shouldn't happen." 822 | 823 | when :terminate 824 | @state.done = true 825 | 826 | when :ensure_west 827 | @state.dir = @state.dir.reflect '|' if @state.dir.vec.x > 0 828 | when :ensure_east 829 | @state.dir = @state.dir.reflect '|' if @state.dir.vec.x < 0 830 | when :ensure_north 831 | @state.dir = @state.dir.reflect '_' if @state.dir.vec.y > 0 832 | when :ensure_south 833 | @state.dir = @state.dir.reflect '_' if @state.dir.vec.y < 0 834 | when :turn_left 835 | @state.dir = @state.dir.left 836 | when :turn_right 837 | @state.dir = @state.dir.right 838 | when :trampoline 839 | @state.skip_next 840 | when :cond_trampoline 841 | @state.skip_next if pop == '' 842 | when :cond_cmp 843 | top = pop 844 | second = pop 845 | if top > second 846 | @state.dir = @state.dir.left 847 | elsif top < second 848 | @state.dir = @state.dir.right 849 | end 850 | when :fold_iterator 851 | @state.add_iterator pop 852 | 853 | when :jump 854 | label = pop 855 | positions = scan_source(label) 856 | if !positions.empty? 857 | push_return 858 | @state.jump(*positions[0]) 859 | end 860 | when :return 861 | @state.jump(*pop_return) 862 | when :jump_raw 863 | label = pop 864 | positions = scan_source(label) 865 | @state.jump(*positions[0]) if !positions.empty? 866 | when :return_raw 867 | @state.jump(*peek_return) 868 | when :push_return 869 | push_return 870 | when :discard_return 871 | pop_return 872 | 873 | when :get_diagonal 874 | label = pop 875 | positions = scan_source(label) 876 | if !positions.empty? 877 | cursor = Point2D.new(*positions[0]) + @state.dir.vec 878 | string = '' 879 | while is_char? @state.cell(cursor) 880 | string << @state.cell(cursor) 881 | cursor += @state.dir.vec 882 | end 883 | push string 884 | end 885 | when :put_diagonal 886 | label = pop 887 | value = pop 888 | positions = scan_source(label) 889 | if !positions.empty? 890 | cursor = Point2D.new(*positions[0]) + @state.dir.vec 891 | value.each_char {|c| 892 | @state.put_cell(cursor, c.ord) 893 | cursor += @state.dir.vec 894 | } 895 | end 896 | 897 | when :store_register 898 | i = @state.rp 899 | pop.each_char do |c| 900 | @state.tape[i] = c.ord 901 | i += 1 902 | end 903 | @state.tape[i] = -1 904 | when :load_register 905 | push @state.read_register 906 | when :register_left 907 | @state.rp -= 1 while is_char? @state.tape[@state.rp-1] 908 | @state.rp -= 1 909 | @state.rp -= 1 while is_char? @state.tape[@state.rp-1] 910 | when :register_right 911 | @state.rp += 1 while is_char? @state.tape[@state.rp] 912 | @state.rp += 1 913 | when :search_left 914 | needle = pop 915 | string = "" 916 | 917 | cursor = @state.rp-1 918 | cursor -= 1 while is_char? @state.tape[cursor-1] 919 | 920 | (cursor-2).downto([*@state.tape.keys, 0].min-1).each do |i| 921 | if is_char?(@state.tape[i]) 922 | string << @state.tape[i] 923 | elsif string.reverse[needle] 924 | @state.rp = i+1 925 | break 926 | else 927 | string = "" 928 | end 929 | end 930 | when :search_right 931 | needle = pop 932 | string = "" 933 | 934 | cursor = @state.rp 935 | cursor += 1 while is_char? @state.tape[cursor] 936 | 937 | (cursor+1..[*@state.tape.keys, 0].max+1).each do |i| 938 | if is_char?(@state.tape[i]) 939 | string << @state.tape[i] 940 | elsif string[needle] 941 | @state.rp = i - string.size 942 | break 943 | else 944 | string = "" 945 | end 946 | end 947 | when :join_tape 948 | push @state.tape.keys.sort.map{|i| @state.tape[i]}.select{|v| is_char?(v)}.map(&:chr_utf_8).join 949 | 950 | when :leave_string_mode 951 | push @state.current_string.select{|c| is_char? c }.map(&:chr_utf_8).join 952 | when :escape 953 | old_ip = @state.ip 954 | old_dir = @state.dir 955 | raw_move 956 | if is_char?(@state.cell) 957 | push @state.cell.chr_utf_8 958 | else 959 | push '' 960 | end 961 | @state.ip = old_ip 962 | @state.dir = old_dir 963 | 964 | when :digit 965 | push(pop + cmd) 966 | 967 | when :input 968 | line = @state.in_str.gets 969 | push(line ? line.scrub('').chomp : '') 970 | when :output 971 | pop.unpack('C*').each{|c| @state.out_str.putc c } 972 | @state.out_str.puts 973 | when :raw_input 974 | str = @state.in_str.read 975 | push(str ? str.scrub('') : '') 976 | when :raw_output 977 | pop.unpack('C*').each{|c| @state.out_str.putc c } 978 | when :argv 979 | arg = ARGV.shift || "" 980 | push(arg.dup.force_encoding(Encoding::UTF_8).scrub('')) 981 | 982 | when :superimpose 983 | top = pop 984 | second = pop 985 | result = "" 986 | [top.size, second.size].max.times do |i| 987 | result << [top[i] || 0.chr_utf_8, second[i] || 0.chr_utf_8].max 988 | end 989 | push result 990 | 991 | when :concat 992 | top = pop 993 | second = pop 994 | push(second + top) 995 | when :drop 996 | y = pop 997 | x = pop 998 | result = x.chars 999 | x.scan(/(?=#{Regexp.escape(y)})/) do 1000 | y.size.times do |i| 1001 | result[$`.size + i] = 0 1002 | end 1003 | end 1004 | 1005 | push (result-[0]).join 1006 | when :riffle 1007 | sep = pop 1008 | push(pop.chars * sep) 1009 | when :occurrences 1010 | sep = pop 1011 | pop.scan(/#{Regexp.escape(sep)}/){ push sep } 1012 | when :split 1013 | sep = pop 1014 | @state.stack += pop.split(sep, -1) 1015 | when :replace 1016 | target = pop 1017 | needle = pop 1018 | haystack = pop 1019 | push haystack.gsub(needle, target) 1020 | when :trim 1021 | push pop.gsub(/\A[ \n\t]+|[ \n\t]+\z/, '') 1022 | when :transliterate 1023 | target = pop 1024 | source = pop 1025 | string = pop 1026 | if !string.empty? 1027 | if target.empty? 1028 | source.each_char {|c| string.gsub!(c, '')} 1029 | else 1030 | max_char_count = string.chars.uniq.map{|c| string.count c}.max 1031 | source *= max_char_count 1032 | target *= source.size / target.size + 1 1033 | string = string.chars.map{ |c| 1034 | if (i = source.index c) 1035 | d = target[i] 1036 | source[i] = '' 1037 | target[i] = '' 1038 | d 1039 | else 1040 | c 1041 | end 1042 | }.join 1043 | end 1044 | end 1045 | push string 1046 | when :discard_up_to 1047 | y = pop 1048 | x = pop 1049 | 1050 | i = x.index y 1051 | x[0,i+y.size] = '' if i 1052 | 1053 | push x 1054 | 1055 | when :find 1056 | needle = pop 1057 | haystack = pop 1058 | push(haystack[needle] || '') 1059 | when :truncate_to_shorter 1060 | top = pop 1061 | second = pop 1062 | length = [top.size, second.size].min 1063 | push second[0,length] 1064 | push top[0,length] 1065 | when :zip 1066 | top = pop.chars 1067 | second = pop.chars 1068 | result = [] 1069 | while !top.empty? || !second.empty? 1070 | result << (second.shift || '') 1071 | result << (top.shift || '') 1072 | end 1073 | push result * '' 1074 | when :unzip 1075 | str = pop 1076 | left = '' 1077 | right = '' 1078 | str.scan(/(.)(.|\z)/m) do 1079 | left << $1 1080 | right << $2 1081 | end 1082 | push left 1083 | push right 1084 | 1085 | when :shortest_common_superstring 1086 | top = pop 1087 | second = pop 1088 | len = [top.size, second.size].min 1089 | len.downto(0) do |i| 1090 | if second[-i,i] == top[0,i] 1091 | push second+top[i..-1] 1092 | break 1093 | end 1094 | end 1095 | when :longest_common_substring 1096 | top = pop 1097 | second = pop 1098 | second.size.downto(0) do |l| 1099 | if l == 0 1100 | push "" 1101 | else 1102 | shared = second.chars.each_cons(l).select {|s| top[s.join]} 1103 | if !shared.empty? 1104 | shared.uniq.each{|s| push s.join} 1105 | break 1106 | end 1107 | end 1108 | end 1109 | 1110 | when :intersection 1111 | second = pop 1112 | first = pop 1113 | result = first.chars.select {|c| 1114 | test = second[c] 1115 | second[c] = '' if test 1116 | test 1117 | } 1118 | push result.join 1119 | when :union 1120 | second = pop 1121 | first = pop 1122 | first.each_char {|c| second[c] = '' if second[c]} 1123 | push(first + second) 1124 | when :symdifference 1125 | second = pop 1126 | first = pop 1127 | 1128 | temp_second = second.clone 1129 | 1130 | first.each_char {|c| second[c] = '' if second[c]} 1131 | temp_second.each_char {|c| first[c] = '' if first[c]} 1132 | 1133 | push first+second 1134 | when :complement 1135 | second = pop 1136 | first = pop 1137 | second.each_char {|c| first[c] = '' if first[c]} 1138 | 1139 | push first 1140 | 1141 | when :deduplicate 1142 | push pop.chars.uniq.join 1143 | 1144 | when :sort 1145 | push pop.chars.sort.join 1146 | 1147 | when :shuffle 1148 | push pop.chars.shuffle.join 1149 | when :random_choice 1150 | push pop.chars.sample || '' 1151 | 1152 | when :characters 1153 | @state.stack += pop.chars 1154 | when :runs 1155 | pop.scan(/(.)\1*/m){push $&} 1156 | when :head 1157 | str = pop 1158 | if str == '' 1159 | push '' 1160 | push '' 1161 | else 1162 | push str[0] 1163 | push str[1..-1] 1164 | end 1165 | when :tail 1166 | str = pop 1167 | if str == '' 1168 | push '' 1169 | push '' 1170 | else 1171 | push str[0..-2] 1172 | push str[-1] 1173 | end 1174 | 1175 | when :lower_case 1176 | push pop.downcase 1177 | when :upper_case 1178 | push pop.upcase 1179 | when :swap_case 1180 | push pop.swapcase 1181 | 1182 | when :not 1183 | push(pop == '' ? 'Jabberwocky' : '') 1184 | 1185 | when :reverse 1186 | push pop.reverse 1187 | when :permutations 1188 | @state.stack += pop.chars.permutation.map{|p| p.join}.to_a 1189 | when :subsequences 1190 | str = pop.chars 1191 | (0..str.size).each do |l| 1192 | str.combination(l).each {|s| push s.join} 1193 | end 1194 | when :substrings 1195 | str = pop.chars 1196 | (1..str.size).each do |l| 1197 | str.each_cons(l).each {|s| push s.join} 1198 | end 1199 | when :permute 1200 | top = pop 1201 | second = pop 1202 | push (0...second.size).stable_sort_by{|i| 1203 | c = top[i] 1204 | c ? c.ord : 1114112 # Value greater than any code point, so that trailing 1205 | # characters remain in place. 1206 | }.map{|i| second[i]}.join 1207 | 1208 | when :expand_ranges 1209 | val = pop 1210 | push val.chars.map(&:ord).each_cons(2).map{ |a,b| 1211 | if a > b 1212 | (b..a).drop(1).to_a.reverse.select{|c|is_char? c}.map(&:chr_utf_8).join 1213 | else 1214 | (a...b).to_a.select{|c|is_char? c}.map(&:chr_utf_8).join 1215 | end 1216 | }.join + (val[-1] || '') 1217 | 1218 | 1219 | when :swap 1220 | top = pop 1221 | second = pop 1222 | push top 1223 | push second 1224 | when :dup 1225 | top = pop 1226 | push top.clone 1227 | push top.clone 1228 | when :discard 1229 | pop 1230 | when :push_joined_stack 1231 | push @state.stack.join 1232 | when :reverse_stack 1233 | @state.stack.reverse!.map!{|x|x.to_s} 1234 | when :permute_stack 1235 | top = pop 1236 | max_size = [@state.stack.size, top.size].max 1237 | @state.stack = (-max_size..-1).stable_sort_by{|i| 1238 | c = top[i] 1239 | c ? c.ord : -1 # Value less than any code point, so that leading 1240 | # stack elements remain in place. 1241 | }.map{|i| @state.stack[i] || ''} 1242 | 1243 | when :datetime 1244 | push DateTime.now.strftime '%Y-%m-%dT%H:%M:%S.%L%:z' 1245 | when :const_lf 1246 | push "\n" 1247 | when :const_empty 1248 | push "" 1249 | 1250 | end 1251 | end 1252 | end 1253 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Alice 2 | 3 | "...the slithy toves did gyre and gimble in the wabe." — Lewis Carroll 4 | 5 | Alice is a two-dimensional, stack-based, recreational programming language. It was designed as a feature-rich [Fungeoid](https://esolangs.org/wiki/Fungeoid) with many useful (and some not so useful) commands which make it comparably usable for a 2D language. To this end, depending on whether the instruction pointer moves orthogonally or diagonally, Alice operates either in an integer mode or in a string mode, which allows every operator to be overloaded with two different commands. 6 | 7 | ## Language concepts 8 | 9 | This section introduces some general concepts about Alice's programming model. 10 | 11 | One quick definition up front: Alice considers an integer value to be a *character* if it is in one of the inclusive ranges [0, 55295] or [57344, 1114111], which is the entire range of Unicode code points. 12 | 13 | ### Source code and grid 14 | 15 | The source file is assumed to be encoded as UTF-8 (as are the standard input and output strings of an Alice program). And linefeeds (0x0A) are considered to be the only line separators. If the lines aren't all of the same length, the shorter ones are padded on the right with spaces (0x20). If the file is empty it is treated as a file containing a single space. 16 | 17 | Each character is then converted to its Unicode code point and the resulting values are placed on an infinite 2D grid. The first character of the source file goes at coordinate **(0,0)**, the **x** coordinate increases along lines (to the right) and the **y** coordinate increases across lines (downwards). Any cells not covered by the (padded) source file are filled with `-1`. 18 | 19 | For example the following source file... 20 | 21 | ABC 22 | D 23 | EF 24 | 25 | ...would lead to the following initial grid: 26 | 27 | x ... -2 -1 0 1 2 3 4 ... 28 | y 29 | ... 30 | -2 -1 -1 -1 -1 -1 -1 -1 31 | -1 -1 -1 -1 -1 -1 -1 -1 32 | 0 -1 -1 65 66 67 -1 -1 33 | 1 -1 -1 68 32 32 -1 -1 34 | 2 -1 -1 69 70 32 -1 -1 35 | 3 -1 -1 -1 -1 -1 -1 -1 36 | 4 -1 -1 -1 -1 -1 -1 -1 37 | ... 38 | 39 | While it's possible to access the entire unbounded grid over the course of program execution, in the following *"the grid"* will refer to the smallest rectangle that contains all values which aren't `-1`. There will always be a finite number of such cells, so this is well-defined. However, the grid *may* grow or shrink during program execution if the grid values are modified such that the bounding box of non-`-1` cells changes. 40 | 41 | Characters and their character codes will be used interchangeably when it comes to cells in the remainder of this document. So a cell containing the value `65` might also be referred to as a cell containing `A`. 42 | 43 | There are a few different types of grid cells. Their exact meanings will be explained below, but we'll define them here: 44 | 45 | - **No-ops:** Spaces (0x20), backticks (`` ` ``, 0x60) and every value which is *not* in the printable ASCII range (0x20 to 0x7E) is considered a no-op. They generally don't do anything (except backticks) and are treated specially during movement. 46 | - **Geometry:** `_` and `|` are **walls** and `/` and `\` are **mirrors**. In particular, these are not considered to be commands (as in most other Fungeoids) but have a special status and are considered to be part of the "geometry" of the grid. 47 | - **Commands:** Every other printable ASCII character is considered to be a command. `'` and `"` have a somewhat special status among these, but we'll get to those when we talk about movement. 48 | 49 | ### Cardinal and Ordinal mode 50 | 51 | Alice's defining feature is that it can operate in two different modes: 52 | 53 | - If the instruction pointer is moving horizontally or vertically, Alice operates in **Cardinal mode**. In this mode, Alice treats all data as integers and can perform operations related to arithmetic, number theory, combinatorics etc. 54 | - If the instruction pointer is moving diagonally, Alice operates in **Ordinal mode**. In this mode, Alice treats all data as strings and can perform operations related to string processing, array manipulation and set theory (treating strings as lists or multisets of characters). 55 | 56 | Alice switches between the two modes by stepping through *mirrors* (of course). Consequently, the two modes were designed to feel somewhat like two parallel universes, where many things look and feel the same but are actually subtly (or not so subtly) different. Every command (except for some very basic stack manipulation) has two different meanings in the two modes, movement works somewhat differently and memory is interpreted in a different way. 57 | 58 | The parallels between Cardinal and Ordinal mode were designed with a few themes in mind. For example, Ordinal-mode commands which work with substrings are often paired with similar Cardinal-mode commands that work with divisors, bitwise commands are paired set-theoretic commands and so on. 59 | 60 | ### Memory model 61 | 62 | Alice's memory model spans three types of storage. 63 | 64 | #### Data types 65 | 66 | There are two data types in Alice: arbitrary-precision signed integers and strings. A string is simply a list of characters (as defined above). 67 | 68 | #### Grid 69 | 70 | We've already seen the grid as the way the source code is interpreted. However, the grid can be written to and read from (even outside of the bounds of the initial grid), which means that it doubles as memory storage. Each cell can hold a single integer. 71 | 72 | #### Stack 73 | 74 | As a stack-based language, Alice's primary memory storage is a single [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)). The stack can hold both integers and strings. However, Cardinal mode and Ordinal mode only know about one of these types. So when they try pop a value, Alice might implicitly convert the value to the appropriate type. The rules for this conversion are as follows. 75 | 76 | If a string is popped in Cardinal mode, Alice finds all integers in this string. Integers are substrings consisting only of ASCII digits, optionally prefixed by a `-`. However, if the `-` immediately follows an earlier integer, it is ignored. An example might help: in `ab12,-34cd`, Alice would find the integers `12` and `-34`. But in `ab12-34cd` it would find the integers `12` and `34` instead. All of these integers are pushed to the stack (from left to right), and then Alice tries to pop a value again. Note that if the string on top of the stack contains no integers, it will simply be discarded and Alice pops the next value instead (which may again be a string which would repeat the process). 77 | 78 | If Alice tries to pop from an empty stack in Cardinal mode, a zero is returned instead. Likewise, commands which work with the stack without popping treat it as if there as in infinite amount of zeros at the bottom. 79 | 80 | If an integer is popped in Ordinal mode, Alice simply converts that integer to its usual decimal string representation. 81 | 82 | If Alice tries to pop from an empty stack in Ordinal mode, an empty string is returned instead. Likewise, commands which work with the stack without popping treat it as if there as in infinite amount of empty strings at the bottom. 83 | 84 | Note that there are few stack manipulation commands which reorder the stack *without* popping any values. Consequently, these don't cause any type conversion. This will be pointed out explicitly in the command reference, where applicable. 85 | 86 | #### Tape 87 | 88 | As a secondary memory storage, Alice has an infinite tape of integers. As opposed to a tape-based language like [Brainfuck](http://esolangs.org/wiki/Brainfuck), Alice's tape is more used like an unlimited amount of registers. Data can be copied to and from the tape but cannot be manipulated directly on the tape. The tape is initially filled with the value `-1` in every cell. 89 | 90 | There are two independent tape heads (or memory pointers), one for Cardinal mode and one for Ordinal mode. When the current mode is clear from the context, the corresponding one will just be referred to as "the tape head". Initially, both tape heads point at the cell at index zero. 91 | 92 | Cardinal and Ordinal mode treat the data on the tape differently. Whereas Cardinal mode just considers each cell as a separate integer, Ordinal mode treats the tape as a tape of words. 93 | 94 | **Words** are defines as consecutive runs of cells that correspond to characters, terminated by a cell that *isn't* a character. Therefore negative values and values greater than **1114111** are considered word terminators. If there are two adjacent non-character cells, the latter represents an empty word. 95 | 96 | ### Additional state 97 | 98 | Apart from the the memory storages above, there are a few more pieces of program state in Alice, which are described in this section. 99 | 100 | #### Instruction pointer 101 | 102 | Control flow in Alice is governed by an instruction pointer (**IP**), which has a position on the grid as well as a direction. To avoid confusion with directions relative to the IP, we'll use *north* (**-y**), *east* (**+x**), *south* (**+y**) and *west* (**-x**) to refer to absolute directions on the grid. 103 | 104 | #### Return address stack 105 | 106 | Alice has an internal stack of grid coordinates which are used as return addresses. These allow you to implement reusable subroutines relatively conveniently. Note that all of this is only by convention. Alice has no concept of scope, and there is nothing stopping the IP from leaving a subroutine "on its own" without making use of the return address stack. The stack is merely a convenience so that the programmer does not have to keep track of where to resume execution of the code manually. 107 | 108 | The return address stack is initially empty and can hold pairs of integers, i.e. (x,y) coodinates on the grid. Note in particular that the return address stack stores no information about the IP's direction. 109 | 110 | If a command attempts to pop from this stack when it's empty, the current position of the IP will be returned instead (which essentially makes "return" commands on an empty stack no-ops). 111 | 112 | #### Iterator queue 113 | 114 | While normally each command in Alice is executed once when the IP passes over it, Alice has **iterators** which let you execute a command multiple times in a row. 115 | 116 | There is an internal [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)), which can hold integers and strings and which is initially empty. If the queue is empty, the default iterator is **1**. The detailed semantics of these iterators are explained below in the section on [executing commands](#commands). 117 | 118 | ### Movement 119 | 120 | The IP is initially at coordinate (-1,0), i.e. left of the first character of the program, moving east. Because the IP always moves before a command is executed, this effectively means the program starts at coordinate (0,0), as you'd expect. 121 | 122 | Alice is executed in "ticks" where each tick consists of a move, followed by executing a command. A move consists of one or more steps and essentially scans the grid for the next command in the direction of the IP. However, grid geometry (i.e. walls, mirrors or boundaries) may change the direction of the IP and even the mode while it moves. 123 | 124 | There is a special case if the IP is initially on a cell containing `'`. If this is the case, the IP will move one step, completely ignoring the contents of the next cell (whether they are no-op, geometry or command, even another `'`), before starting its usual scan for the next command. This is because `'` is an "escaping" command which also consumes the next cell. 125 | 126 | If the IP encounters the special command `"` on its search, it will activate **string mode**, which is described in more detail below. Activating string mode is not considered a command (although deactivating it is). 127 | 128 | #### No-ops 129 | 130 | The IP skips over all no-ops while it searches for the next command. However, there is one special no-op here: the backtick, `` ` ``. Whenever the IP passes over a backtick, Alice prints debug information about all relevant program state to the standard error stream. The exact representation is up to the interpreter, but it should contain all of Alice's state. Interpreters with interactive debuggers may instead choose to interpret backticks as breakpoints. 131 | 132 | #### Walls 133 | 134 | These are simplest: if the IP encounters `_` or `|` during a move, its direction gets reflected as you'd expect. In Cardinal mode, `_` is ignored for horizontal movement and `|` reverses the direction (and vice-versa for vertical movement). In Ordinal mode, they change the direction by 90 degrees, e.g. `_` changes southeast movement to northeast etc. 135 | 136 | #### Mirrors 137 | 138 | Mirrors, `/` and `\`, are a staple in 2D languages, but in Alice they work a bit differently than you probably expect. First of all, in Alice the IP moves *through* mirrors and doesn't get reflected at them. But secondly, Alice acknowledges that the characters `/` and `\` are rarely displayed at 45 degree angles, so having them cause 90 degree reflections is somewhat unfitting. The angles in many fonts are actually closer to 67.5 degrees, and therefore mirrors reflect between orthogonal and diagonal movement in Alice. 139 | 140 | Unfortunately, this may look slightly confusing in the source code at first, because most fonts (even monospaced ones) also don't have square character cells. Therefore, here are 16 diagrams which visualise every possible way the IP can enter a mirror: 141 | 142 | [![Movement through mirrors][mirrors]][mirrors] 143 | Click for larger version 144 | 145 | If this reflection seems weird (especially the acute-angled cases), imagine holding a long straight stick with one end to the surface of a mirror. The IP comes in along that stick and when it hits the surface of the mirror it goes "into" the mirror and continues along the reflection of the stick. 146 | 147 | Note that this always changes orthogonal movement to diagonal movement and vice versa. Therefore, mirrors always toggle between Cardinal mode and Ordinal mode, and they are also the *only* way in the language to switch between modes. 148 | 149 | [mirrors]: https://i.stack.imgur.com/YHx0d.png 150 | 151 | #### Boundaries 152 | 153 | While the IP is moving it may happen that it tries to move to a cell outside of the grid (i.e. beyond the bounding box of non-background cells in the unbounded grid). 154 | 155 | How Alice handles this situation depends on whether we are in Cardinal mode and Ordinal mode. 156 | 157 | Cardinal mode uses wrapping boundaries like many other Fungeoids. If the IP is out of bounds after a step, it moves to the beginning of the line (which may be a row or column) along which it is currently moving instead. Note that this means that if the IP moves alongside the grid (instead of away from it or towards it), it will be stuck outside the grid forever. This situation can be caused by some of the control flow commands, or if the grid shrinks while the IP moves along its edge. 158 | 159 | Ordinal mode uses solid boundaries instead, which act similarly to walls. If the IP would move out of bounds with the current step, its direction will instead be reflected on the boundary before taking the step. If the IP would move through a corner of the grid, its direction gets reversed. 160 | 161 | If the grid is only one cell tall or wide, it is not possible for the IP to take any diagonal steps so the IP will remain in place. If the current cell is a command, that command would get executed over and over again (but setting this up is quite non-trivial and should be considered a tremendous edge case). If the IP manages to end up out of bounds by more than one cell (which is also a very unlikely edge case), it will be stuck there forever. 162 | 163 | ### Commands 164 | 165 | Once movement ends and the IP has found a command, that command will be executed. When a command needs to be executed, Alice first dequeues an iterator from the iterator queue. Remember that if the queue is empty, the default iterator is **1** (which in effect means that the command is simply executed once as you'd expect). 166 | 167 | How the command is executed depends on the iterator: 168 | 169 | - **Repetition:** If the iterator is a positive integer **N**, the command is executed **N** times (without moving the IP in between, unless the command itself causes movement). For non-positive integers, the command isn't executed at all. 170 | - **Folding:** If the iterator is a string, Alice goes through each character in the string from left to right and then a) pushes that character to the stack and b) executes the current command once. Note that if the iterator is an empty string this also means that the command isn't executed at all. 171 | 172 | The iterator queue will normally contain at most one value, which lets you execute the next command multiple times. However, if that next command itself adds iterators to the queue, it's possible to have multiple iterators queued up at once. 173 | 174 | Some commands can put a **0** at the front of the queue (so it's not a strict queue), in order to skip the next command. 175 | 176 | ### String mode 177 | 178 | Finally, there is string mode, which can be entered and exited with the special `"` command. In string mode, Alice no longer executes any of the usual commands but instead remembers each cell value it passes over until string mode ends again. However, a few characters retain their special meaning: 179 | 180 | - `'` still escapes the next cell. The `'` itself is not added to the string, but the subsequent cell is, even if it's a special character. 181 | - Mirrors and walls (i.e. any of `/\_|`) still redirect the IP without being added to the string, unless they are escaped with `'`. In particular, this means that it's possible to switch between Cardinal and Ordinal mode while string mode is active. 182 | - `"` ends string mode (unless it's escaped) and processes the list of integers that has been recorded. 183 | 184 | Remember that entering string mode is not considered a command for the purpose of iterators, but leaving string mode is. The consequences are that leaving string mode dequeues an iterator (and therefore may process the string several times), and how the string is processed depends on whether we're in Cardinal or Ordinal mode at the time of leaving string mode. 185 | 186 | If string mode ends in Cardinal mode, the resulting command pushes each of the recorded integers once to the stack. 187 | 188 | If string mode ends in Ordinal mode, the resulting command discards all integers that aren't valid characters and pushes the remainder as a single string to the stack. 189 | 190 | ### Labels 191 | 192 | While Cardinal mode uses integer coordinate pairs to address cells in the grid (e.g. to manipulate the grid or for certain control flow commands), Ordinal mode has no concept of integers. Instead, Ordinal mode uses **labels** to refer to positions on the grid. 193 | 194 | A label is just a string that appears somewhere on the grid, but since Ordinal mode operates along diagonals, labels are also searched for along diagonals. When a command tries to find a certain label, it effectively rotates the grid by a multiple of 45 degrees so that the IP points east, and then searches for the label in normal (left-to-right, top-to-bottom) reading order. To make it explicit, the following four grids show in which order the grid is scanned depending on the IP's current direction: 195 | 196 | Direction: SE SW NW NE 197 | 198 | Scanning gdba pnkg jmop acfj 199 | order: khec olhd filn beim 200 | nlif mieb cehk dhlo 201 | pomj jfca abdg gknp 202 | 203 | Note that labels cannot span multiple lines. For example, it would not be possible to find the label `cde` in any of the above grids. Alice will only search the strings `a`, `bc`, `def`, `ghij`, `klm`, `no` and `p` for the label. Commands will either refer to the cell after the label (along its diagonal), or to the one directly before that (so in general, the end of the label is the relevant reference point). The exact usage of the label is described below for the relevant commands. 204 | 205 | ## Command reference 206 | 207 | This section lists all the commands available in Alice, roughly grouped into a few related categories. For the sake of completeness, the non-commands `` ` `` (which is a special no-op), `/\_|` (which are mirrors and walls) and the special commands `'` and `"` are listed here again, but remember that they are treated differently for the purposes of movement. 208 | 209 | If the reference says "Pop **n**" in Cardinal mode, **n** is always an integer. In Ordinal mode, it's always a string. See the section [on the stack](#stack) for details of potentially required type conversions. In general, **n** will be used as the variable of single integer parameters, and **x**, **y**, **z** if there are several. Similarly, **s** will be used for a single string parameter, and **a**, **b**, **c** if there are several. There are some exceptions, where other variables are more conventional, like using **n** and **k** in the context of combinatorics. 210 | 211 | When the reference refers to pushing individual characters to the stack, this refers to strings containing only that character. 212 | 213 | ### Debugging 214 | 215 | Cmd | Cardinal | Ordinal 216 | --- | -------- | ------- 217 | `` ` `` | **Debug.** Special no-op: prints debug information to the standard error stream. | **Debug.** Same as Cardinal. 218 | 219 | ### Control flow 220 | 221 | Cmd | Cardinal | Ordinal 222 | --- | -------- | ------- 223 | `@` | **End.** Terminate the program. | **End.** Terminate the program. 224 | `/` | **Mirror.** Reflect the IP through 67.5 degrees, switch between modes. See section [on mirrors](#mirrors) for details. | **Mirror.** Same as Cardinal. 225 | `\` | **Mirror.** Reflect the IP through -67.5 degrees, switch between modes. See section [on mirrors](#mirrors) for details. | **Mirror.** Same as Cardinal. 226 | `_` | **Wall.** Reflect the IP through 0 degrees. See section [on walls](#walls) for details. | **Wall.** Same as Cardinal. 227 | `\|` | **Wall.** Reflect the IP through 90 degrees. See section [on walls](#walls) for details. | **Wall.** Same as Cardinal. 228 | `<` | **Move west.** Set the IP direction to west. | **Half-wall west.** Set the horizontal component of the IP direction to west. 229 | `>` | **Move east.** Set the IP direction to east. | **Half-wall east.** Set the horizontal component of the IP direction to east. 230 | `^` | **Move north.** Set the IP direction to north. | **Half-wall north.** Set the vertical component of the IP direction to north. 231 | `v` | **Move south.** Set the IP direction to south. | **Half-wall south.** Set the vertical component of the IP direction to south. 232 | `{` | **Turn left.** Rotate the IP direction left by 90 degrees. | **Turn left.** Rotate the IP direction left by 90 degrees. 233 | `}` | **Turn right.** Rotate the IP direction right by 90 degrees. | **Turn right.** Rotate the IP direction right by 90 degrees. 234 | `=` | **Sign junction.** Pop **n**. Act like `{` if **n** is negative, like `}` if **n** is positive. Has no further effect if **n = 0**. | **Compare junction.** Pop **b**. Pop **a**. Act like `{` if **a < b**, act like `}` if **a > b**. Has no further effect if **a = b**. Comparisons are based on the lexicographic ordering of the strings. 235 | `#` | **Skip.** Skip the next command. This is implemented by adding a **0** to the *front* of the iterator queue. | **Skip.** Same as Cardinal. (Technically, this one uses **""** as the iterator, but **""** and **0** are functionally equivalent as iterators.) 236 | `$` | **Skip if 0.** Pop **n**. Act like `#` if **n = 0**, do nothing otherwise. | **Skip if empty.** Pop **s**. Act like `#` if **s = ""**, do nothing otherwise. 237 | `j` | **Jump.** Pop **y**. Pop **x**. Push the current IP address to the return address stack. Jump to **(x,y)**.\* | **Jump.** Pop **s**. Search the grid for the label **s**. If the label is not found, do nothing. Otherwise, push the current IP address to the return address stack and jump to the last cell of the label. See the section [on labels](#labels) for details.\* 238 | `J` | **Raw jump.** Same as `j`, but does not push the current IP to the return address stack.\* | **Raw jump.** Same as `j`, but does not push the current IP to the return address stack.\* 239 | `k` | **Return.** Pop an address from the return address stack and jump there.\* | **Return.** Same as Cardinal. 240 | `K` | **Raw return.** Peek at the top of the return address stack and jump there.\* | **Raw return.** Same as Cardinal. 241 | `w` | **Push return address.** Push the current IP address to the return address stack (without jumping anywhere). | **Push return address.** Same as Cardinal. 242 | `W` | **Discard return address.** Pop and discard the top of the return address stack. | **Discard return address.** Same as Cardinal. 243 | `&` | **Repeat.** Pop **n**. Add **n** to the iterator queue. | **Fold.** Pop **s**. Add **s** to the iterator queue. 244 | 245 | \* Remember that the IP will then move *before* the next command is executed. 246 | 247 | ### Literals and constants 248 | 249 | Cmd | Cardinal | Ordinal 250 | --- | -------- | ------- 251 | `"` | **Toggle string mode.** Only exiting string mode is considered a command, and pushes all the recorded integers to the stack. See the section [on string mode](#string-mode) for details. | **Toggle string mode.** Only exiting string mode is considered a command, and pushes all recorded integers that are valid characters as a single string to the stack. See the section [on string mode](#string-mode) for details. 252 | `'` | **Escape.** Pushes the value of the next grid cell to the stack. | **Escape.** If the next grid cell holds a valid character, that character is pushed to the stack. Otherwise, an empty string is pushed. 253 | `0-9` | **Digit.** Pushes the corresponding digit to the stack. | **Digit.** Pop **s**. Append the corresponding digit as a character to **s** and push the result. 254 | `a` | **Ten.** Push **10**. | **Linefeed.** Push a single linefeed character (0x0A). 255 | `e` | **Minus one.** Push **-1**. | **Empty string.** Push **""**. 256 | 257 | The next cell will be skipped by the subsequent move, but not as part of the command. This distinction is important when working with iterators. 258 | 259 | ### Input and output 260 | 261 | Cmd | Cardinal | Ordinal 262 | --- | -------- | ------- 263 | `i` | **Read byte.** Read a single byte from the standard input stream and push it. Push `-1` at EOF instead. | **Read all.** Read the entire UTF-8-encoded standard input stream (until EOF is encountered) and push it as a single string. 264 | `I` | **Read character.** Read a single UTF-8-encoded character from the standard input stream and push its code point. Push `-1` at EOF instead. | **Read line.** Read one UTF-8-encoded line from the standard input stream (i.e. up to the first linefeed, 0x0A) and push it as a single string. The linefeed is consumed but not included in the resulting string. 265 | `o` | **Write byte.** Pop **n**. Write its 8 least significant bits as a byte to the standard output stream. | **Write string.** Pop **s**. Write it as a UTF-8-encoded string to the standard output stream. 266 | `O` | **Write character.** Pop **n**. If **n** is a valid character, write it to the standard output stream using UTF-8 encoding. | **Write line.** Pop **s**. Write it as a UTF-8-encoded string to the standard output stream, followed by a linefeed (0x0A). 267 | `M` | **ARGC.** Push the number of remaining command-line arguments.§ | **ARGV.** Push the first unread command-line argument, or **""** if all arguments have been read.§ The arguments are assumed to be encoded in UTF-8. Any bytes that do not form a valid UTF-8 character will be skipped. 268 | 269 | This will skip any bytes that do not form a valid UTF-8 character. 270 | § These do not include any parts of the command that are necessary to invoke the program itself (including its file name). 271 | 272 | ### Grid manipulation 273 | 274 | 275 | Cmd | Cardinal | Ordinal 276 | --- | -------- | ------- 277 | `g` | **Get cell.** Pop **y**. Pop **x**. Get the value in the grid cell at **(x,y)** and push it. | **Get diagonal.** Pop **s**. Scan the grid for the label **s**. If the label was found, start reading characters after the end of the label (along the same diagonal) until a non-character value is found. Push the string formed by those characters to the stack. See the section [on labels](#labels) for details. 278 | `p` | **Put cell.** Pop **y**. Pop **x**. Pop **v**. Set the value in the grid cell at **(x,y)** to **v**. | **Put diagonal.** Pop **s**. Pop **v**. Scan the grid for the label **s**. If it is found, write **v** onto the grid, one character per cell, starting at the cell after the label (on the same diagonal). If **v** is longer than the remainder of the diagonal, this will write over the edge of the grid and thereby extend the bounding box of the grid. See the section [on labels](#labels) for details. 279 | 280 | ### Stack manipulation 281 | 282 | Cmd | Cardinal | Ordinal 283 | --- | -------- | ------- 284 | `,` | **Rotate stack.** Pop **n**. If **n** is positive, move the element which is **n** elements below the top to the top. If **n** is negative, move the top stack element down the stack by **n** positions. These operations do not pop and push elements and therefore don't convert any data types. | **Permute stack.** Pop **s**. Use as a permutation to reorder the stack. This is done by aligning the string character-by-character with the stack elements, so that the last element corresponds to the top of the stack (and the first character corresponds to the **n**th element from the top, where **n** is the length of **s**). Then the string is sorted stably, while keeping each stack element paired with its corresponding character. Hence, the stack elements perform the reordering that is required to sort **s**. The reordered stack elements are not popped in the process, so this does not convert any data types. 285 | `~` | **Swap.** Pop **y**. Pop **x**. Push **y**. Push **x**. | **Swap.** Pop **b**. Pop **a**. Push **b**. Push **a**. 286 | `.` | **Duplicate.** Pop **n**. Push **n** twice. | **Duplicate.** Pop **s**. Push **s** twice. 287 | `;` | **Discard.** Pop one integer and discard it. | **Discard.** Pop one string and discard it. 288 | `Q` | **Convert.** Pop **n**. Pop **n** values and push them again, so that their order *remains the same*. This can be used to force conversion of stack elements from the top such that there are at least **n** integers on top of the stack (as opposed to strings). | **Reverse stack.** Pop all stack elements and push them again, so that their order is *reversed*. This also forces conversion to strings, although there are no cases where an explicit conversion to strings can change the behaviour of a program. 289 | `d` | **Depth.** Push the number of elements currently in the stack (without popping or converting any of them). | **Join stack.** Make a copy of each stack element, convert it to a string, join them all together (so that the top element is at the end) and push the result. This does not affect any of the existing stack elements. 290 | 291 | ### Tape manipulation 292 | 293 | Cmd | Cardinal | Ordinal 294 | --- | -------- | ------- 295 | `!` | **Store.** Pop **n**. Store it in the current tape cell. | **Store.** Pop **s**. Store it as a word on the tape. In particular, store its characters on the tape, starting at the position of the tape head and going right. The cell right after the end of **s** gets set to **-1** to ensure that there is a word terminator. 296 | `?` | **Load.** Push the value in the current tape cell to the stack. | **Load.** Read a word from the tape cell by taking the longest run of characters from the position of the tape head to the right and push it to the stack. 297 | `[` | **Move left.** Move the tape head one cell to the left. | **Move left.** Move the tape head one word to the left. Specifically, move the tape head left as long as that cell holds a character (to move the tape head to the beginning of the current word) — this part will usually be skipped. Then move it one more cell to the left (to move it onto the previous word terminator). Then move it left again as long as that cell holds a character (to move the tape head to the beginning of the previous word). 298 | `]` | **Move right.** Move the tape head one cell to the right. | **Move right.** Move the tape head one word to the right. Specifically, move the tape head right as long as the current cell holds a character (to move the tape head to the terminator of the current word). Then move it one more cell to the right (to move it onto the beginning of the next word). 299 | `(` | **Search left.** Pop **n**. Search for **n** left of the tape head (excluding the current cell itself). If it is found, move the tape head to the nearest occurrence. Note that **-1** can always be found in the infinite stretches of unwritten tape to either side of the modified part. | **Search left.** Pop **s**. Search for a word containing **s** as a substring left of the currently pointed to word (excluding that word itself). If such a word is found, move the tape head to its beginning. 300 | `)` | **Search right.** Pop **n**. Search for **n** right of the tape head (excluding the current cell itself). If it is found, move the tape head to the nearest occurrence. Note that **-1** can always be found in the infinite stretches of unwritten tape to either side of the modified part. | **Search right.** Pop **s**. Search for a word containing **s** as a substring right of the currently pointed to word (excluding that word itself). If such a word is found, move the tape head to its beginning. 301 | `q` | **Tape head.** Push the current *position* of the tape head. | **Join tape.** Join all words on the tape into a single string and push it. 302 | 303 | ### Basic arithmetic and string operations 304 | 305 | Cmd | Cardinal | Ordinal 306 | --- | -------- | ------- 307 | `+` | **Add**. Pop **y**. Pop **x**. Push **x + y**. | **Superimpose.** Pop **b**. Pop **a**. Add null characters to the end of the shorter string until they are the same length. Then form a new string by taking the character with the larger code point at each position, and push that string. 308 | `-` | **Subtract.** Pop **y**. Pop **x**. Push **x - y**. | **Remove.** Pop **b**. Pop **a**. Remove all occurrences of **b** from **a** and push the result. If there are overlapping occurrences, the characters from all those occurrences will be removed (e.g. operands **"abcbcbd"** and **"bcb"** would yield **"ad"**). 309 | `*` | **Multiply.** Pop **y**. Pop **x**. Push **x * y**. | **Concatenate.** Pop **b**. Pop **a**. Push the concatenation of **a** and **b**. 310 | `:` | **Divide.** Pop **y**. Pop **x**. Push **x / y**. Results are rounded towards negative infinity. Terminates the program with an error if **y = 0**. | **Occurrences.** Pop **b**. Pop **a**. Push all *non-overlapping* occurrences of **b** in **a** (e.g. operands **"abcbcbcbd"** and **"bcb"** would push **"bcb"** only twice). 311 | `%` | **Modulo.** Pop **y**. Pop **x**. Push **x % y** (modulo). The sign of the result matches the sign of **y**, such that **(x / y) * y + x % y = x** is guaranteed. Terminates the program with an error if **y = 0**. | **Split.** Pop **b**. Pop **a**. Split **a** into chunks separated by occurrences of **b** and push those chunks. 312 | `E` | **Power/Root.** Pop **y**. Pop **x**. If **y** is non-negative, push **xy**. If **x = y = 0**, push **1**. If **y** is negative and **x** is non-negative, this computes **x1/-y**, rounded towards negative infinity. If both **x** and **y** are negative, this computes **-(-x)1/-y**, rounded towards negative infinity. | **Riffle.** Pop **b**. Pop **a**. Insert **b** between every pair of characters in **a** and push the result. 313 | `H` | **Abs.** Pop **n**. Push **\|n\|**. | **Trim.** Pop **s**. Remove all tabs (0x09), linefeeds (0x0A) and spaces (0x20) from both ends of the string. 314 | `R` | **Negate.** Pop **n**. Push **-n**. | **Reverse.** Pop **s**. Reverse **s** and push the result. 315 | `h` | **Increment.** Pop **n**. Push **n+1**. | **Head.** Pop **s**. Push the first character of **s**, then push the remainder of **s**. If **s == ""**, push **""** twice. 316 | `t` | **Decrement.** Pop **n**. Push **n-1**. | **Tail.** Pop **s**. Push the everything except the last character of **s**, then push the last character of **s**. If **s == ""**, push **""** twice. 317 | `m` | **Floor.** Pop **y**. Pop **x**. Push the greatest multiple of **y** which is not greater than **x**. | **Truncate.** Pop **b**. Pop **a**. Remove characters from the end of the longer string until they have the same length. Push **a**. Push **b**. 318 | `n` | **Logical Not.** Pop **y**. Push **1** if **y = 0**, push **0** otherwise. | **Logical Not.** Pop **s**. Push **"Jabberwocky"** if **s = ""**, push **""** otherwise. 319 | `Y` | **Unpack.** Pop **n**. Map **n** (bijectively) to two integers **x** and **y**. Push **x**. Push **y**. This is the inverse operation of `Z`. For details of the bijection, see the footnote. | **Unzip.** Pop **s**. Create two empty strings **a** and **b**. Append the characters from **s** to **a** and **b** in an alternating manner, starting with **a**. Push **a**. Push **b**. 320 | `Z` | **Pack.** Pop **y**. Pop **x**. Map **x** and **y** (bijectively) to a single integer **n**. Push **n**. This is the inverse operation of `Y`. For details of the bijection, see the footnote. | **Zip.** Pop **b**. Pop **a**. Interleave **a** and **b** by taking characters from then in an alternating manner, starting with **a**. If one string is shorter than the other, the remaining characters of the other one are simply appended. For example **a = "abc"** and **b = "012345"** will yield **"a0b1c2345"**. Push the result. 321 | 322 | The details of the bijection are likely irrelevant for most use cases. The main point is that it lets the user encode two integers in one and extract the two integers again later on. By applying the pack command repeatedly, entire lists or trees of integers can be stored in a single number (although not in a particularly memory-efficient way). The mapping computed by the pack operation is a bijective function **ℤ2 → ℤ** (i.e. a one-to-one mapping). First, the integers **{..., -2, -1, 0, 1, 2, ...}** are mapped to the natural numbers (including zero) like **{..., 3, 1, 0, 2, 4, ...}** (in other words, negative integers are mapped to odd naturals and non-negative integers are mapped to even naturals). The two natural numbers are then mapped to one via the [Cantor pairing function](https://en.wikipedia.org/wiki/Pairing_function), which writes the naturals along the diagonals of the first quadrant of the integer grid. Specifically, **{(0,0), (1,0), (0,1), (2,0), (1,1), (0,2), (3,0), ...}** are mapped to **{0, 1, 2, 3, 4, 5, 6, ...}**. The resulting natural number is then mapped back to the integers using the inverse of the earlier bijection. The unpack command computes exactly the inverse of this mapping. 323 | 324 | ### Bitwise arithmetic, multiset operations and character transformation 325 | 326 | 327 | Cmd | Cardinal | Ordinal 328 | --- | -------- | ------- 329 | `A` | **And.** Pop **y**. Pop **x**. Push the bitwise *AND* of **x** and **y**. | **Intersection.** Pop **b**. Pop **a**. Compute the multiset intersection of **a** and **b** (accounting for multiplicities). Specifically, iterate through the characters of **a** and remove the leftmost copy of each character from **b** if it exists, and remove it from **a** otherwise. Push what remains of **a**. 330 | `N` | **Not.** Pop **n**. Push the bitwise *NOT* of **n**. Equivalent to **-n-1**. | **Complement.** Pop **b**. Pop **a**. Compute the multiset complement of **b** in **a**, or alternatively the multiset difference **b \ a** (accounting for multiplicities). Specifically, iterate through the characters of **b** and remove the leftmost copy of each character from **a** if it exists. Push what remains of **a**. 331 | `V` | **Or.** Pop **y**. Pop **x**. Push the bitwise *OR* of **x** and **y**. | **Union.** Pop **b**. Pop **a**. Compute the multiset union of **a** and **b** (accounting for multiplicities). Specifically, iterate through the characters of **a** and remove the leftmost copy of each character from **b** if it exists. Concatenate **a** and what remains of **b** and push the result. 332 | `X` | **Xor.** Pop **y**. Pop **x**. Push the bitwise *XOR* of **x** and **y**. | **Symmetric difference.** Pop **b**. Pop **a**. Compute the symmetric multiset difference of **a** and **b** (accounting for multiplicities). Specifically, make a copy of **b**, called **b'**, iterate through the characters of **a** and remove the leftmost copy of each character from **b** if it exists. Then iterate through **b'** and remove the leftmost copy of each character from **a** if it exists. Concatenate what remains of **a** and **b** and push the result. 333 | `y` | **If-then-else.** Pop **z**. Pop **y**. Pop **x**. Push the bitwise if-then-else of **x**, **y** and **z**. Specifically, push **(x AND y) OR (NOT x AND z)**. | **Transliterate.** Pop **c**. Pop **b**. Pop **a**. Transliterate **a** by mapping **b** to **c** and push the result. The details of this operation are somewhat involved and can be found in the footnote. 334 | `l` | **Clear lower bits.** Pop **n**. Set all of its bits except the most-significant bit to **0**. Push the result. | **Lower case.** Pop **s**. Convert letters in **s** to lower case. Whether and how this works for Unicode letters outside the ASCII range, and whether the user's locale is respected is implementation-defined. 335 | `u` | **Set lower bits.** Pop **n**. Set all of its bits except the most-significant bit to **1**. Push the result. | **Upper case.** Pop **s**. Convert letters in **s** to upper case. Whether and how this works for Unicode letters outside the ASCII range, and whether the user's locale is respected is implementation-defined. 336 | 337 | Here is how a transliteration is computed. If **c** is empty, remove all copies of the characters in **b** from **a**. Otherwise, repeat **b** often enough so that no character occurs more often in **a** than in **b**. Then repeat **c** often enough so that it is no shorter than **b**. Now create a mapping of each character in **b** to the character in the same position in **c**. Finally, go through the characters in **a**. If the character exists in **b**, replace it with a character from **c** using the leftmost mapping, and then remove that mapping (so that the next copy of this character uses the next mapping and so on). If the character did not exist in **b**, leave it unchanged in **a**. Here is an example: **a = "ABACABADA"**, **b = "ABCA"**, **c = "0123456"**. First, we need to repeat **b** three times so that it contains at least as many **"A"s** as **a**, so we get **b = "ABCAABCAABCA"**. Then we need to repeat **c** twice so that it's at least as long as **b**, so we get **c = "01234560123456"**. This creates the following list of mappings: **[A → 0, B → 1, C → 2, A → 3, A → 4, B → 5, C → 6, A → 0, A → 1, B → 2, C → 3, A → 4]**. Finally, we go through **a** and replace the **i**th occurrence of a character with the **i**th applicable mapping in this list, if it exists. So we end up with **"0132450D1"**. This operation may seem very weird, but it's mostly just a generalisation of several useful character transformation tasks. When both **b** and **c** are the same length, and the characters in **b** are unique, this simply performs a character-by-character transliteration as you might be familiar with from languages like Ruby or sed. To replace digits with their parity, you can use **b = "0123456789"**, **c = "01"**. To fill a string **c** character by character into gaps indicated by underscores in **a**, use **b = "\_"**. 338 | 339 | ### Number theory and advanced string operations 340 | 341 | 342 | Cmd | Cardinal | Ordinal 343 | --- | -------- | ------- 344 | `B` | **Divisors.** Pop **n**. Push all divisors of **n**, in order from smallest to largest. If **n** is negative, all divisors will be pushed negatively as well (still ordered by their absolute magnitude). If **n = 0**, push nothing. | **Substrings.** Pop **s**. Push all non-empty contiguous substrings of **s**, from shortest to longest and from left to right. 345 | `D` | **Deduplicate prime factors.** Pop **n**. As long as **p2** divides **n** for some prime **p**, divide **n** by **p** (that is, remove all "extraneous" copies of prime factors), and push the result. If **n = 0**, push **0**. | **Deduplicate characters.** Pop **s**. For each character, discard all but its first occurrence in **s**. Push the result. 346 | `F` | **Divides.** Pop **y**. Pop **x**. If **y ≠ 0** and **y** divides **x**, push **y**. Otherwise, push **0**. | **Contains.** Pop **b**. Pop **a**. If **a** contains **b** as a substring, push **b**. Otherwise, push **""**. 347 | `G` | **GCD.** Pop **y**. Pop **x**. Push the greatest common divisor of **x** and **y**. If **x = y = 0**, push **0**. The result is always non-negative. | **LCS.** Pop **b**. Pop **a**. Push the longest substring that occurs in both **a** and **b**. If there are multiple common substrings of the maximal length, each such substring is pushed once (even if it appears multiple times), sorted by its first occurrence in **a**. Note that the empty string is always a common substring of **a** and **b**. 348 | `L` | **LCM.** Pop **y**. Pop **x**. Push the least common multiple of **x** and **y**. The result is always non-negative. | **SCS.** Pop **b**. Pop **a**. Push the shortest possible string which starts with **a** and ends with **b**. 349 | `S` | **Replace divisor.** Pop **z**. Pop **y**. Pop **x**. Determine how often **y** divides **x**, i.e. find the largest **n** for which **yn** divides **x**. Divide **x** by **yn** and then multiply it by **zn**. Push the result. There are several special cases: If **x = 0**, push **0**. If **y = z = ±1**, push **x**. If **y = ±1** and **z = 0**, push **0**. In all other cases, where **y = ±1**, enter an infinite loop. | **Replace substring.** Pop **c**. Pop **b**. Pop **a**. Replace each non-overlapping occurrence of **b** in **a** with **c**. Push the result. 350 | `c` | **Prime factors.** Pop **n**. Push the individual prime factors of **n** from smallest to largest (repeating each prime factor as necessary). Special cases: If **n = 0**, push **0**. If **n = 1**, push nothing. If **n < 0** push **-1** followed by the result for **-n**. | **Characters.** Pop **s**. Push the individual characters of **s** separately. 351 | `f` | **Prime-exponent pairs.** Pop **n**. Push the prime factors of **n** as pairs of prime and exponent. Special cases: if **n = 0**, push **0, 1**. If **n = 1**, push nothing. If **n < 0**, push **-1, 1** followed by the result for **-n**. | **Runs.** Pop **s**. Split **s** between any pair of different adjacent characters (or split **s** into runs of equal characters) and push the individual chunks. Do nothing if **s** is empty. 352 | `z` | **Drop small factors.** Pop **y**. Pop **x**. For each prime **p** less than or equal to **y**, divide **x** by **p** as long as possible and push the result. For **y < 0** also uses negative primes **p** so that the sign of **x** is flipped for each removed prime factor. If **x = 0**, push **0**. | **Drop.** Pop **b**. Pop **a**. If **a** contains **b** as a substring, discard everything in **a** up to and including the first occurrence of **b**. Push **a**. 353 | 354 | ### Combinatorics 355 | 356 | Cmd | Cardinal | Ordinal 357 | --- | -------- | ------- 358 | `C` | **Binomial.** Pop **k**. Pop **n**. Push the binomial coefficient **n-choose-k**. Specifically, if **n > 0** and **k > n/2**, replace **k** with **n-k**. Then if **k < 0**, push **0**. If **k = 0**, push **1**. If **k > 0**, multiply the numbers from **n** down to **n-k+1** and divide them by the numbers from **1** to **k**. | **Subsequences.** Pop **s**. Push all (not necessarily contiguous) subsequences of **s** from shortest to longest. Each subsequence should be thought of as a subset of the positions in **s** that are retained, while all others are dropped. The order of subsequences for a given length are such that the corresponding lists of retained positions would be canonically ordered. 359 | `P` | **Factorial.** Pop **n**. Push **n!**. For negative **n**, multiplies the numbers from **n** up to **-1**, so that we get **(-n)!** for even **n** and **-(-n)!** for odd **n**. | **Permutations.** Pop **s**. Push all permutations of **s**, such that if each character was replaced by its index in **s**, the permutations would be canonically ordered. If **s** contains duplicate characters, there will be duplicate permutations. 360 | 361 | ### Order, randomness and time 362 | 363 | Cmd | Cardinal | Ordinal 364 | --- | -------- | ------- 365 | `T` | **Sleep.** Pop **n**. Pause execution for **n** milliseconds. Does nothing if **n** is negative. | **Date and time.** Push the current date and time in the format **"YYYY-MM-DDTHH:MM:SS.mmm±AA:BB"** where **T** is an actual **"T"** and **±AA:BB** indicates the system's time zone. 366 | `U` | **Random integer.** Pop **n**. If **n > 0**, push a uniformly random integer in **[0,n)**. If **n < 0**, push a uniformly random integer in **(n,0]**. If **n = 0**, push **0**. | **Random choice.** Pop **s**. Push a character chosen randomly with uniform distribution from **s**. If **s** contains duplicate characters, these will have a higher probability of being drawn. If **s** is the empty string, push the empty string again. 367 | `b` | **Random swap.** Pop **y**. Pop **x**. With 50% probability, swap **x** and **y**. Push **x**, push **y**. | **Shuffle.** Pop **s**. Shuffle **s** with a uniform distribution of possible resulting strings. Push the result. 368 | `r` | **Range.** Pop **n**. If **n ≥ 0**, push all integers from **0** to **n**, inclusive. If **n < 0**, push all integers from **-n** to **0**, inclusive. | **Range expansion.** Pop **s**. First, reduce all consecutive runs of equal characters to a single copy of that character. Then, for each pair of adjacent characters **a** and **b**, insert all intermediate characters between them. Push the result. For example, **"aebbfbbbda"** becomes **"abcdedcbcdefedcbcdcba"**. 369 | `s` | **Sort swap.** Pop **y**. Pop **x**. If **x > y**, swap **x** and **y**. Push **x**, push **y**. | **Sort.** Pop **s**. Sort the characters in **s**. Push **s**. 370 | `x` | **Extract bit.** Pop **y**. Pop **x**. Extract the **y**th bit from the binary representation of **x**. If **y** is negative, return the **(m+y+1)**th bit, where **m** is the position of the most significant bit of **x**. For **x < -1**, the most-significant bit is the most-significant zero. For **x = -1**, or **x = 0**, **m = -1**. And if **-y > m+1**, this returns **0**. | **Permute string.** Pop **b**. Pop **a**. Reorder **a** according to **b**, similar to the `,` command. This is done by aligning the strings character-by-character. If **a** is shorter than **b**, the last characters of **b** are paired with empty strings. If **b** is shorter than **a**, the remaining characters in **a** will be unaffected. Then **b** is sorted stably, while keeping each of its characters paired with the corresponding character from **a**. Then join the characters (and possibly empty strings) from **a** back together and push the result. Hence, the characters in **a** are reordered by the same permutation that would sort **b**. 371 | 372 | 373 | ## Reference implementation 374 | 375 | This repository also contains a reference implementation of the language in Ruby. 376 | 377 | To run a program, simply invoke the interpreter with the source code's file name as a command-line argument, e.g. 378 | 379 | $ ruby ./interpreter.rb ./examples/hw.alice [args ...] 380 | --------------------------------------------------------------------------------