Caerwyn Jones | 1 Apr 2007 14:59
Picon

Re: blackbox: a game for acme

thanks, this is neat!

i wouldn't mind seeing an acme client similar to this to gnu chess and gnu go.

On 3/31/07, Arvindh Rajesh Tamilmani < arvindht-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
A port of the blackbox game from Emacs.

http://mordor.tip9ug.jp/who/art/inferno/blackbox

Requires acmeevent.b, ported from plan9port:

http://mordor.tip9ug.jp/who/art/inferno/acmeevent.b

From Emacs help:

        Blackbox is a game of hide and seek played on an 8 by 8
        grid (the blackbox).  Your opponent has hidden several
        balls (usually 4) within this box.  By shooting rays
        into the box and observing where they emerge it is
        possible to deduce the positions of the hidden balls.
        The fewer rays you use to find the balls, the lower
        your score.

To shoot a ray, middle-click on the edges of the box.
To place or remove a ball, middle-click inside the box.
Once you've placed 4 balls, middle-click on Score to get the score.

The possible outcomes for each ray are explained in the
commentary (in the header) and doc comment
(under 'defun blackbox') here:

http://cvs.savannah.gnu.org/viewcvs/emacs/emacs/lisp/play/blackbox.el?view=markup

Comments welcome.
Arvindh

==== blackbox ====

#!/dis/sh

load std
load expr

fn msg{
        echo blackbox: $*
}

# rand(mod): a random number between 0 and mod-1
subfn rand{
        mod := $1
        r := `{read 1 </dev/random | sum /fd/0}
        result = ${expr 16r${hd $r} $mod %}
}

# a random point within the blackbox
subfn randpt{
        result = ${expr ${rand 8} 1 +} ${expr ${rand 8} 1 +}
}

# convert a character address to a point
subfn topt{
        addr := $1
        result = ${expr $addr 21 % 2 /} ${expr $addr 21 /}
}

# convert a point (x y) to a compound address of n characters
subfn toaddr{
        (x y n) := $*
        q0 := ${expr $y 21 x $x 2 x +}
        q1 := ${expr $q0 $n +}
        result = '#'$q0',#'$q1
}

# replace n characters at (x y) with s
fn mark{
        (x y s n) := $*
        echo -n ${toaddr $x $y $n} >$wdir/addr
        echo -n $s >$wdir/data
        echo clean >$wdir/ctl
}

# ismember(ax ay l): true if (ax ay) is a member of l
fn ismember{
        (ax ay l) := $*
        (x y) := ()
        stat := no
        while{ntest $#l}{
                (x y l) = $l
                if{and {~ $ax $x} {~ $ay $y}}{
                        stat = ()
                        raise break
                }
        }
        status $stat
}

# del(ax ay l): delete (ax ay) from l
subfn del{
        (ax ay l) := $*
        (x y) := ()
        while{ntest $#l}{
                (x y l) = $l
                if{and {~ $ax $x} {~ $ay $y}}{
                        result = ($result $l)
                        raise break
                }{
                        result = ($x $y $result)
                }
        }
}

# given l1 and l2, mark the points unique in l1 with c
subfn comm-2{
        (s1 s2 c) := $*
        l1 := ${split ' ' $s1}
        l2 := ${split ' ' $s2}
        (x y) := ()
        result = 0
        while{ntest $#l1}{
                (x y l1) = $l1
                if{! ismember $x $y $l2}{
                        mark $x $y $c 1
                        result = ${expr $result 1 +}
                }
        }
}

fn drawbox{
        echo -n , >$wdir/addr
        echo -n >$wdir/data

        echo '  · · · · · · · ·   ' >$wdir/body
        for i in b l a c k b o x {
                echo '· - - - - - - - - · ' >$wdir/body
        }
        echo '  · · · · · · · ·   ' >$wdir/body
        echo clean >$wdir/ctl
}

# hide 4 balls in distinct random points
fn hideballs{
        for i in b a l l {
                b := ${randpt}
                while {ismember $b $balls}{
                        b = ${randpt}
                }
                balls = ($b $balls)
        }
}

fn iscorner{
        (x y) := $*
        and (
                {or {~ $x 0}{~ $x 9}}
                {or {~ $y 0}{~ $y 9}}
        )
}

fn isout{
        (x y) := $*
        or {~ $x 0}{~ $x 9}{~ $y 0}{~ $y 9}
}

subfn delta{
        n := $1
        if{~ $n 0}{
                result = 1
        }{~ $n 9}{
                result = -1
        }{
                result = 0
        }
}

fn event{
        if{~ $1$2 MX}{
                handlex ${topt $3}
        }{~ $1$2 Mx}{
                if{~ $9 Quit}{
                        echo delete >$wdir/ctl
                        exit
                }{~ $9 NewGame}{
                        newgame
                }{~ $9 Score}{
                        score
                }{
                        echo $1$2$3 $4 >$wdir/event
                }
        }
}

fn handlex{
        pt := $*
        if{iscorner $pt}{
                # do nothing
        }{isout $pt}{
                traceray $pt
        }{
                if{ismember $pt $guess}{
                        mark $pt - 1
                        guess = ${del $pt $guess}
                }{
                        mark $pt O 1
                        guess = ($pt $guess)
                }
        }
}

fn traceray{
        (x y) := $*
        target := ${traceray0 true $x ${delta $x} $y ${delta $y}}
        if{~ $target hit}{
                mark $x $y H 1
                score = ${expr $score 1 +}
        }{and {~ ${hd $target} $x} {~ ${tl $target} $y}}{
                mark $x $y R 1
                score = ${expr $score 1 +}
        }{
                detour = ${expr $detour 1 +}
                if{~ $detour 100}{
                        msg you''''ve run out of rays.
                }{
                        n := 1
                        if{~ ${expr $detour 9 gt} 1}{
                                n = 2
                        }
                        mark $x $y $detour $n
                        mark $target $detour $n
                        score = ${expr $score 2 +}
                }
        }
}

subfn traceray0{
        (first x dx y dy) := $*

        if{and {~ $first false} {isout $x $y}}{
                result = $x $y
        }{ismember ${expr $x $dx +} ${expr $y $dy +} $balls}{
                result = hit
        }{ismember ${expr $x $dx + $dy +} ${expr $y $dy + $dx +} $balls}{
                result = ${traceray0 false $x ${expr $dy _} $y ${expr $dx _}}
        }{ismember ${expr $x $dx + $dy -} ${expr $y $dy + $dx -} $balls}{
                result = ${traceray0 false $x $dy $y $dx}
        }{
                result = ${traceray0 false ${expr $x $dx +} $dx ${expr $y $dy +} $dy}
        }
}

fn score{
        if{~ $#guess $#balls}{
                missed := ${comm-2 $"guess $"balls X}
                {} ${comm-2 $"balls $"guess <at> }
                if{ntest $missed}{
                        msg you missed $missed 'ball(s); '^
                                your score is ${expr $missed 5 x $score +}^.
                }{
                        msg congrats! your score is $score^.
           &nbs
Arvindh Rajesh Tamilmani | 1 Apr 2007 21:24
Picon

Re: blackbox: a game for acme

> i wouldn't mind seeing an acme client similar to this to gnu chess and gnu
> go.

an acme chess client is in my wish list too, mainly because the chess
pieces are available in unicode.


Gmane