(this is a resend of a message that got caught in the moderation queue)

I have a friend who occasionally runs programming competitions for kids,
and when he's putting together exercises he sometimes runs them by us
just to see what we'll come up with. The other day he posted
a description of a simple task and I thought I'd have a go. I got it
working in Python very neatly, but then I decided I'd see if I could
figure out how to do the same in Factor.

Here's the problem description:

    Code Golf Challenge #1
    ======================

    Write something that will:

    * Encode stdin into chunks like so:
        01      1 octet         SOH
        xxxx    2 octets        chunk number (monotonically increasing)
        xx      1 octet         chunk length
        ...     <256 octets     up to 255 bytes of data
        xx      1 octet         checksum (8-bit sum of all data bytes)
      
      with an "end of transmission" marker of:
        04      1 octet         EOT
        xxxx    2 octets        chunk number
        00      1 octet         length 0

    * optionally shuffle chunks
    * base64-encode output

    Your entry should be *readable*.  Use any standard libraries you want.

    Par 78 SLOC (ANSI C).  It relies on standard Unix tools and pipes.

For what it's worth, I'm told this algorithm is very similar to the
ancient XMODEM file-transfer protocol.  Yes, 'readable' conflicts with
'code golf'; at least for the Factor version I'm trying to prefer
readability over brevity. Also, comparing my implementation to the
sample ANSI C implementation, it turns out there are extra rules:

    - chunk length is actually capped at 128 bytes
    - the uint16 chunk length should be stored in big-endian order

Here's my Factor implementation. It works (that is, it produces
identical output to the reference implementation), but it's not very
pretty (note that I've ignored the 'shuffle' feature, and base64
encoding is done with an external tool, same as the reference
implementation):

    USING: arrays io io.encodings io.encodings.binary kernel locals
        make math pack sequences syntax ;
    IN: bmodem

    CONSTANT: WINDOW 128

    ! Splits stdin into an array of WINDOW-sized byte-arrays.
    : read-chunks ( -- seq )
        [ [ WINDOW read dup f = [ ] [ , t ] if ] loop ] { } make
        ;

    ! Takes a sequence of payload byte-arrays and frames each one
    ! with a packet-header and check-sum.
    ! Also adds the trailer ("EOT") packet.
    : format-packets ( seq -- seq' )
        [
            [
                [| payload index |
                    1 index payload length 3array "CSC" pack-be %
                    payload %
                    payload sum 256 mod ,
                ] B{ } make
            ] map-index
        ]
        [ length 4 swap 0 3array "CSC" pack-be ] bi
        suffix
        ;

    ! Slurp bytes from stdin, spit packets to stdout.
    : main ( -- )
        binary decode-input read-chunks 
        binary encode-output format-packets [ write ] each
        ;

    MAIN: main

In particular, the way read-chunks breaks out of the loop when it's hit
EOF strikes me as ugly, what with the if word's quotations having
different stack signatures. Also, there's still a few stack-shuffling
words lurking about in there. I'm not sure if that's within standard
tolerances, or if I'm doing something wrong.

Any hints or suggestions?

------------------------------------------------------------------------------
Try before you buy = See our experts in action!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-dev2
_______________________________________________
Factor-talk mailing list
Factor-talk@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/factor-talk

Reply via email to