Talk:DownRight

From Esolang
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)