#!/usr/bin/env ruby trap("INT") do quit end def quit hfile = File.join(ENV['HOME'], ".goforthanddie_history") File.open(hfile, ?w) do |f| f.puts(Readline::HISTORY.to_a) f.flush end exit end def getlist(stack, markermode, markerautoclear) if markermode h = [] wm = false loop do break if stack.empty? t = stack.pop wm = t == :mark break if wm h << t end stack.push(:mark) if wm && !markerautoclear h.reverse else n = stack.pop stack.pop(n) end end def handle(str, stack, markermode, markerautoclear, destructiveprint) str.split.each do |token| case token when /\A[+-]?[0-9]+\Z/ stack.push(token.to_i) when "+", "add", "plus" a, b = stack.pop(2) stack.push(a + b) when ".+", ".add", ".plus", ".sum" h = getlist(stack, markermode, markerautoclear) stack.push(h.sum) when "-", "sub", "subtract", "minus" a, b = stack.pop(2) stack.push(a - b) when "*", "mul", "multiply", "times" a, b = stack.pop(2) stack.push(a * b) when "/", "div", "divide" a, b = stack.pop(2) stack.push(a / b) when "%", "mod", "modulate", "rem", "remainder" a, b = stack.pop(2) stack.push(a % b) when "d", "roll" n = stack.pop d = stack.pop n.times { stack.push(rand(d) + 1) } when "c", "copy", "dup" h = stack.pop stack.push(h) stack.push(h) when ".c", ".copy", ".dup" h = getlist(stack, markermode, markerautoclear) stack.push(*h) stack.push(:mark) if markermode && !markerautoclear stack.push(*h) when "s", "swap" a, b = stack.pop(2) stack.push(b, a) when "r", "rot", "rotate" a, b, c = stack.pop(3) stack.push(b, c, a) when ".r", ".rot", ".rotate" c = stack.pop h = getlist(stack, markermode, markerautoclear) stack.push(*h.rotate(c)) when "o", "over" a, b = stack.pop(2) stack.push(a, b, a) when "p", "print" t = stack.pop puts t stack.push(t) unless destructiveprint when ".ex", ".explode" x = stack.pop h = getlist(stack, markermode, markerautoclear) lm = 0 loop do m = h.count(x) break if m == lm (m-lm).times { h << (rand(x) + 1) } lm = m end stack.push(*h) when ".k", ".kh", ".keep", ".keephigh", ".keephighest" k = stack.pop h = getlist(stack, markermode, markerautoclear) h.sort! stack.push(*h.pop(k)) when ".kl", ".keeplow", ".keeplowest" k = stack.pop h = getlist(stack, markermode, markerautoclear) h.sort! stack.push(*h.shift(k)) when ".>", ".gt", ".greaterthan" c = stack.pop h = getlist(stack, markermode, markerautoclear) stack.push(*h.select{ |d| d > c }) when ".>=", ".gteq", ".greaterthanorequalto" c = stack.pop h = getlist(stack, markermode, markerautoclear) stack.push(*h.select{ |d| d >= c }) when ".=", ".eq", ".equalto" c = stack.pop h = getlist(stack, markermode, markerautoclear) stack.push(*h.select{ |d| d == c }) when ".<=", ".lteq", ".lessthanorequalto" c = stack.pop h = getlist(stack, markermode, markerautoclear) stack.push(*h.select{ |d| d <= c }) when ".<", ".lt", ".lessthan" c = stack.pop h = getlist(stack, markermode, markerautoclear) stack.push(*h.select{ |d| d < c }) when ".count" h = getlist(stack, markermode, markerautoclear) stack.push(h.count) when "!", "drop" stack.pop when ".!", ".drop" getlist(stack, markermode, markerautoclear) when "m", "mark" stack.push(:mark) when /\A'(.*)/ file = File.readlines(File.join(ENV['HOME'], ".goforthanddie")) cmd = file.map { |line| line.split(?:) }.to_h[$1] if cmd.nil? puts "You haven't told me how to #{$1}!" else markermode, markerautoclear, destructiveprint = handle(cmd, stack, markermode, markerautoclear, destructiveprint) end when "~s", "~stack" puts stack.join(" ") when "~mm", "~markermode" markermode = !markermode when "~mac", "~markerautoclear" markerautoclear = !markerautoclear when "~dp", "~destructiveprint" destructiveprint = !destructiveprint when "~state" print "Stack: " pp stack print "Marker Mode: #{markermode ? "ON " : "OFF"} " puts "Marker Auto-Clear: #{markerautoclear ? "ON " : "OFF"}" puts "Destructive Print: #{destructiveprint ? "ON " : "OFF"}" when "~user" puts "User definitions:" file = File. readlines(File.join(ENV['HOME'], ".goforthanddie")). map { |line| line.split(?:) } namemax = file.map {|defn| defn[0].length}.max + 1 file.each do |name, defn| puts " %#{namemax}s: #{defn}" % "'#{name}" end when "~q", "~quit" quit else puts "I don't know how to #{token}!" end end [markermode, markerautoclear, destructiveprint] end stk = [] mm = true mac = false dp = true if $stdin.tty? begin require "readline" rescue LoadError Gem.install "readline" Gem.install "readline-ext" retry end hfile = File.join(ENV['HOME'], ".goforthanddie_history") if File.exist?(hfile) File.readlines(hfile).each do |line| Readline::HISTORY << line.strip end end while buf = Readline.readline("> ", true) mm, mac, dp = handle(buf, stk, mm, mac, dp) end quit else mm, mac, dp = handle($stdin.read, stk, mm, mac, dp) end