Talk:DownRight
Jump to navigation
Jump to search
A partial interpreter in Python
An interesting language here, very elegant. I made an interpreter in Python but it's partial because it doesn't handle the arrows as unicode but instead uses letters 'd' and 'r', and the program input isn't checked for errors, and it's plainly required in different format from the one the language specification uses. But otherwise it should work!
# partialDownRight
# -to feed program, use the following format: [below a 3x2 program example]
# rd d d
# d r rdd
# (that is, use "d" and "r" characters for down and right arrows, separate each string
# within a row with a single space, use a new-line to end the row (except the last row))
# -this interpreter does not deal properly with faulty programs
# -usage: dori.py prog.dr
# use any string (such as "debug") as a second argument to active debug mode
# written by Keymaker
import sys
if len(sys.argv) < 2:
print "Error, need a DownRight program to run."
sys.exit()
try:
f = open(sys.argv[1])
except IOError:
print "Error in reading the program."
sys.exit()
d = f.read().split("\n")
f.close()
debug = 0
if len(sys.argv) > 2:
debug = 1
prog = []
que = ""
width = -1
height = -1
px = 0
py = 0
# this routine does not really check for any errors or invalid syntax...
height = len(d)
for x in d:
a = x.split(" ")
if len(a) > 0:
width = len(a)
for y in a:
prog.append(y)
if debug:
print "program, width, height:", prog, width, height
# -------------------------------------------------------------------
# here should be a routine to check that width and height are coprime
# -------------------------------------------------------------------
que = prog[0] # place the top-left string into the queue
if debug:
print "initial queue:", que
print ""
while 1:
# first, pop the queue
c = ""
if len(que) > 0:
c = que[0]
que = que[1:]
# "" means the queue was empty: halt
if c == "":
if debug:
print "empty queue, program halted"
break
# "d" or "r" mean the instruction pointer will be moved
if c == "d":
if debug:
print "down arrow read from queue"
py = (py + 1) % height
else:
if debug:
print "right arrow read from queue"
px = (px + 1) % width
if debug:
print "instruction pointer gone to", px, py
# now, the string from the new location of the instruction pointer will be placed in the queue
if debug:
print "queue before addition:", que
print "string under instruction pointer:", prog[(width * py) + px]
print "queue: (below)"
que = que + prog[(width * py) + px]
print que
if debug:
print ""
--Keymaker 18:43, 12 May 2011 (UTC)
Implementation in haskell
This should work, the code is likely suboptimal, as I'm not very used to Haskell yet. Tested on GHC 6.12.1 and Parsec 3.0.1.
To use, compile with ghc and then run as ./program < inputfile
This program implements the extension where the sides do not need to be co-prime.
-- Copyright (c) 2011, Vorpal
-- Released in public domain in countries where that is applicable.
import Text.ParserCombinators.Parsec
import qualified Data.Sequence as Seq
import Data.Array
import System.IO
data DownRightReturn = ParseErr ParseError | Error String | FinalPos (Int, Int)
-- Parsec stuff
ws = many (char ' ')
ws1 = many1 (char ' ')
eol = (many1 (char '\n')) >> ws
cell = many1 (noneOf " \n")
line = sepEndBy1 cell ws1
downrightFile = (sepEndBy1 line eol) <|> (eof >> return [])
parseDownRight :: String -> Either ParseError [[String]]
parseDownRight input = parse downrightFile "(unknown)" input
-- Post-procesing parsed stuff
filterDownRight :: [[String]] -> [[String]]
filterDownRight = map (map (filter (`elem` "↓→")))
checkLen :: [[a]] -> Bool
checkLen [] = True
checkLen (x:xs) =
let l = length x in
all (\y -> length y == l) xs
programToArray :: [[String]] -> Array (Int, Int) String
programToArray program =
let (x:_) = program
h = length program - 1
w = length x - 1 in
listArray ((0,0),(h,w)) (concat program)
-- Actual execution
executeDownRight :: Array (Int, Int) String -> Seq.Seq Char -> (Int, Int) -> (Int,Int) -> (Int,Int)
executeDownRight program queue pos max =
case Seq.viewl queue of
Seq.EmptyL -> pos
(Seq.:<) instr newqueue ->
let newpos = calcMove instr pos max
str = program ! newpos in
executeDownRight program ((Seq.><) newqueue (Seq.fromList str)) newpos max
calcMove :: Char -> (Int, Int) -> (Int, Int) -> (Int, Int)
calcMove '→' (x,y) (mx,my) = (x, (y+1) `rem` my)
calcMove '↓' (x,y) (mx,my) = ((x+1) `rem` mx, y)
-- Code wrapping executeDownRight
runDownRight :: Array (Int, Int) String -> (Int, Int)
runDownRight program =
let (_,(mx,my)) = bounds program
str = program ! (0,0) in
executeDownRight program (Seq.fromList str) (0,0) (mx+1,my+1)
downRight :: String -> DownRightReturn
downRight input =
case parseDownRight input of
Left err -> ParseErr err
Right [] -> Error "Can't handle null program yet"
Right (x:xs) ->
case checkLen (x:xs) of
False -> Error "All lines must be of same length"
True ->
FinalPos (runDownRight $ programToArray $ filterDownRight (x:xs))
-- Stuff for running as free standing program instead of from ghci
downRightInteract :: String -> String
downRightInteract input =
case downRight input of
ParseErr err -> "Parse error: " ++ show err ++ "\n"
Error err -> "Error: " ++ err ++ "\n"
FinalPos pos -> "Halted at " ++ show pos ++ "\n"
main = interact downRightInteract
-- User:Vorpal 2011-05-14T12:53:05 (UTC)