I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

# Black Box

Black Box is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Implement a version of the Black Box game beginners configuration: 4 Atoms in an 8 x 8 grid.

Determine where the hidden atoms are in the box, by observing how the light beams fired into the box react when leaving it.
Possible results:
'H': the beam hit an atom and stopped
'R': Either the beam was reflected back the way it came or there was a ball just to one side of its entry point
'Numbers': indicate that the beam entered one of those squares and emerged from the other

Extra credit (Different game types):
-More or less atoms (maybe random)
-Different grid sizes

## Go

Terminal based game.

Just the basic configuration - 4 atoms in an 8 x 8 grid.

To test it against known output (as opposed to playing a sensible game), the program has been fixed (wikiGame = true) to reproduce the atom position in the Wikipedia article's example game, followed by a complete set of beams and one incorrect and three correct guesses.

Set wikiGame to false to play a normal 'random' game.

`package main import (    "bufio"    "fmt"    "log"    "math/rand"    "os"    "strings"    "time") var (    b        = make([]rune, 100) // displayed board    h        = make([]rune, 100) // hidden atoms    scanner  = bufio.NewScanner(os.Stdin)    wikiGame = true // set to false for a 'random' game) func initialize() {    for i := 0; i < 100; i++ {        b[i] = ' '        h[i] = 'F'    }    if !wikiGame {        hideAtoms()    } else {        h[32] = 'T'        h[37] = 'T'        h[64] = 'T'        h[87] = 'T'    }    fmt.Println(`    === BLACK BOX ===     H    Hit (scores 1)    R    Reflection (scores 1)    1-9, Detour (scores 2)    a-c  Detour for 10-12 (scores 2)    G    Guess (maximum 4)    Y    Correct guess    N    Incorrect guess (scores 5)    A    Unguessed atom     Cells are numbered a0 to j9.    Corner cells do nothing.    Use edge cells to fire beam.    Use middle cells to add/delete a guess.    Game ends automatically after 4 guesses.    Enter q to abort game at any time.    `)} func drawGrid(score, guesses int) {    fmt.Printf("      0   1   2   3   4   5   6   7   8   9 \n")    fmt.Printf("\n")    fmt.Printf("        ╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗\n")    fmt.Printf("a     %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c\n",        b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9])    fmt.Printf("    ╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗\n")    fmt.Printf("b   ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║\n",        b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19])    fmt.Printf("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣\n")    fmt.Printf("c   ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║\n",        b[20], b[21], b[22], b[23], b[24], b[25], b[26], b[27], b[28], b[29])    fmt.Printf("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣\n")    fmt.Printf("d   ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║\n",        b[30], b[31], b[32], b[33], b[34], b[35], b[36], b[37], b[38], b[39])    fmt.Printf("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣\n")    fmt.Printf("e   ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║\n",        b[40], b[41], b[42], b[43], b[44], b[45], b[46], b[47], b[48], b[49])    fmt.Printf("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣\n")    fmt.Printf("f   ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║\n",        b[50], b[51], b[52], b[53], b[54], b[55], b[56], b[57], b[58], b[59])    fmt.Printf("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣\n")    fmt.Printf("g   ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║\n",        b[60], b[61], b[62], b[63], b[64], b[65], b[66], b[67], b[68], b[69])    fmt.Printf("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣\n")    fmt.Printf("h   ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║\n",        b[70], b[71], b[72], b[73], b[74], b[75], b[76], b[77], b[78], b[79])    fmt.Printf("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣\n")    fmt.Printf("i   ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║\n",        b[80], b[81], b[82], b[83], b[84], b[85], b[86], b[87], b[88], b[89])    fmt.Printf("    ╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝\n")    fmt.Printf("j     %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c ║ %c\n",        b[90], b[91], b[92], b[93], b[94], b[95], b[96], b[97], b[98], b[99])    fmt.Printf("        ╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝\n")    status := "In play"    if guesses == 4 {        status = "Game over!"    }    fmt.Println("\n        Score =", score, "\tGuesses =", guesses, "\t Status =", status, "\n")} func hideAtoms() {    placed := 0    for placed < 4 {        a := 11 + rand.Intn(78) // 11 to 88 inclusive        m := a % 10        if m == 0 || m == 9 || h[a] == 'T' {            continue        }        h[a] = 'T'        placed++    }} func nextCell() int {    var ix int    for {        fmt.Print("    Choose cell : ")        scanner.Scan()        sq := strings.ToLower(scanner.Text())        if len(sq) == 1 && sq[0] == 'q' {            log.Fatal("program aborted")        }        if len(sq) != 2 || sq[0] < 'a' || sq[0] > 'j' || sq[1] < '0' || sq[1] > '9' {            continue        }        ix = int((sq[0]-'a')*10 + sq[1] - 48)        if atCorner(ix) {            continue        }        break    }    check(scanner.Err())    fmt.Println()    return ix} func atCorner(ix int) bool { return ix == 0 || ix == 9 || ix == 90 || ix == 99 } func inRange(ix int) bool { return ix >= 1 && ix <= 98 && ix != 9 && ix != 90 } func atTop(ix int) bool { return ix >= 1 && ix <= 8 } func atBottom(ix int) bool { return ix >= 91 && ix <= 98 } func atLeft(ix int) bool { return inRange(ix) && ix%10 == 0 } func atRight(ix int) bool { return inRange(ix) && ix%10 == 9 } func inMiddle(ix int) bool {    return inRange(ix) && !atTop(ix) && !atBottom(ix) && !atLeft(ix) && !atRight(ix)} func play() {    score, guesses := 0, 0    num := '0'outer:    for {        drawGrid(score, guesses)        ix := nextCell()        if !inMiddle(ix) && b[ix] != ' ' { // already processed            continue        }        var inc, def int        switch {        case atTop(ix):            inc, def = 10, 1        case atBottom(ix):            inc, def = -10, 1        case atLeft(ix):            inc, def = 1, 10        case atRight(ix):            inc, def = -1, 10        default:            if b[ix] != 'G' {                b[ix] = 'G'                guesses++                if guesses == 4 {                    break outer                }            } else {                b[ix] = ' '                guesses--            }            continue        }        var x int        first := true        for x = ix + inc; inMiddle(x); x += inc {            if h[x] == 'T' { // hit                b[ix] = 'H'                score++                first = false                continue outer            }            if first && (inMiddle(x+def) && h[x+def] == 'T') ||                (inMiddle(x-def) && h[x-def] == 'T') { // reflection                b[ix] = 'R'                score++                first = false                continue outer            }            first = false            y := x + inc - def            if inMiddle(y) && h[y] == 'T' { // deflection                switch inc {                case 1, -1:                    inc, def = 10, 1                case 10, -10:                    inc, def = 1, 10                }            }            y = x + inc + def            if inMiddle(y) && h[y] == 'T' { // deflection or double deflection                switch inc {                case 1, -1:                    inc, def = -10, 1                case 10, -10:                    inc, def = -1, 10                }            }        }        if num != '9' {            num++        } else {            num = 'a'        }        if b[ix] == ' ' {            score++        }        b[ix] = num        if inRange(x) {            if ix == x {                b[ix] = 'R'            } else {                if b[x] == ' ' {                    score++                }                b[x] = num            }        }    }    drawGrid(score, guesses)    finalScore(score, guesses)} func check(err error) {    if err != nil {        log.Fatal(err)    }} func finalScore(score, guesses int) {    for i := 11; i <= 88; i++ {        m := i % 10        if m == 0 || m == 9 {            continue        }        if b[i] == 'G' && h[i] == 'T' {            b[i] = 'Y'        } else if b[i] == 'G' && h[i] == 'F' {            b[i] = 'N'            score += 5        } else if b[i] == ' ' && h[i] == 'T' {            b[i] = 'A'        }    }    drawGrid(score, guesses)} func main() {    rand.Seed(time.Now().UnixNano())    for {        initialize()        play()    inner:        for {            fmt.Print("    Play again y/n : ")            scanner.Scan()            yn := strings.ToLower(scanner.Text())            switch yn {            case "n":                return            case "y":                break inner            }        }        check(scanner.Err())    }}`
Output:

As the grid is displayed 29 times in all, this has been abbreviated to show just the first 2 and the last 3.

```    === BLACK BOX ===

H    Hit (scores 1)
R    Reflection (scores 1)
1-9, Detour (scores 2)
a-c  Detour for 10-12 (scores 2)
G    Guess (maximum 4)
Y    Correct guess
N    Incorrect guess (scores 5)
A    Unguessed atom

Cells are numbered a0 to j9.
Corner cells do nothing.
Use edge cells to fire beam.
Use middle cells to add/delete a guess.
Game ends automatically after 4 guesses.
Enter q to abort game at any time.

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║   ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 0 	Guesses = 0 	 Status = In play

Choose cell : b0

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║   ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 2 	Guesses = 0 	 Status = In play

Choose cell : c0

................ (Screens 3 to 26 omitted) ................

Score = 32 	Guesses = 2 	 Status = In play

Choose cell : g4

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║ H ║ 9 ║ H ║ 7 ║ 9 ║ H ║ 8 ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║ 8 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║ H ║ G ║   ║   ║   ║   ║   ║ G ║   ║ H ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║ 3 ║   ║   ║   ║   ║   ║   ║   ║   ║ 6 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║ 4 ║   ║   ║   ║   ║   ║   ║   ║   ║ 7 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║ H ║   ║   ║   ║ G ║   ║   ║   ║   ║ H ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║ 5 ║   ║   ║   ║   ║   ║   ║   ║   ║ 6 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║ H ║   ║   ║   ║   ║   ║   ║   ║   ║ H ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║ 3 ║ H ║ 5 ║ H ║ 4 ║ R ║ H ║ R ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 32 	Guesses = 3 	 Status = In play

Choose cell : i7

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║ H ║ 9 ║ H ║ 7 ║ 9 ║ H ║ 8 ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║ 8 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║ H ║ G ║   ║   ║   ║   ║   ║ G ║   ║ H ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║ 3 ║   ║   ║   ║   ║   ║   ║   ║   ║ 6 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║ 4 ║   ║   ║   ║   ║   ║   ║   ║   ║ 7 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║ H ║   ║   ║   ║ G ║   ║   ║   ║   ║ H ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║ 5 ║   ║   ║   ║   ║   ║   ║   ║   ║ 6 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║ H ║   ║   ║   ║   ║   ║   ║ G ║   ║ H ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║ 3 ║ H ║ 5 ║ H ║ 4 ║ R ║ H ║ R ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 32 	Guesses = 4 	 Status = Game over!

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║ H ║ 9 ║ H ║ 7 ║ 9 ║ H ║ 8 ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║ 8 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║ H ║ N ║ A ║   ║   ║   ║   ║ Y ║   ║ H ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║ 3 ║   ║   ║   ║   ║   ║   ║   ║   ║ 6 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║ 4 ║   ║   ║   ║   ║   ║   ║   ║   ║ 7 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║ H ║   ║   ║   ║ Y ║   ║   ║   ║   ║ H ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║ 5 ║   ║   ║   ║   ║   ║   ║   ║   ║ 6 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║ H ║   ║   ║   ║   ║   ║   ║ Y ║   ║ H ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║ 3 ║ H ║ 5 ║ H ║ 4 ║ R ║ H ║ R ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 37 	Guesses = 4 	 Status = Game over!

Play again y/n : n
```

## JavaScript

Play it here.

` var sel, again, check, score, done, atoms, guesses, beamCnt, brdSize; function updateScore( s ) {    score += s || 0;    para.innerHTML = "Score: " + score;}function checkIt() {    check.className = "hide";    again.className = "again";    done = true;    var b, id;    for( var j = 0; j < brdSize; j++ ) {        for( var i = 0; i < brdSize; i++ ) {            if( board[i][j].H ) {                b = document.getElementById( "atom" + ( i + j * brdSize ) );                b.innerHTML = "&#x2688;";                if( board[i][j].T ) {                    b.style.color = "#0a2";                } else {                    b.style.color = "#f00";                     updateScore( 5 );                }            }         }    }}function isValid( n ) {    return n > -1 && n < brdSize;}function stepBeam( sx, sy, dx, dy ) {    var s = brdSize - 2    if( dx ) {        if( board[sx][sy].H ) return {r:"H", x:sx, y:sy};        if( ( (sx == 1 && dx == 1) || (sx == s && dx == -1) ) && ( ( sy > 0 && board[sx][sy - 1].H ) ||             ( sy < s && board[sx][sy + 1].H ) ) ) return {r:"R", x:sx, y:sy};        if( isValid( sx + dx ) ) {            if( isValid( sy - 1 ) && board[sx + dx][sy - 1].H ) {                dx = 0; dy = 1;            }            if( isValid( sy + 1 ) && board[sx + dx][sy + 1].H ) {                dx = 0; dy = -1;            }            sx += dx;            return stepBeam( sx, sy, dx, dy );        } else {            return {r:"O", x:sx, y:sy};        }    } else {        if( board[sx][sy].H ) return {r:"H", x:sx, y:sy};         if( ( (sy == 1 && dy == 1) || (sy == s && dy == -1) ) && ( ( sx > 0 && board[sx - 1][sy].H ) ||            ( sx < s && board[sx + 1][sy].H ) ) ) return {r:"R", x:sx, y:sy};        if( isValid( sy + dy ) ) {            if( isValid( sx - 1 ) && board[sx - 1][sy + dy].H ) {                dy = 0; dx = 1;            }            if( isValid( sx + 1 ) && board[sx + 1][sy + dy].H ) {                dy = 0; dx = -1;            }            sy += dy;            return stepBeam( sx, sy, dx, dy );        } else {            return {r:"O", x:sx, y:sy};        }    }}function fireBeam( btn ) {    var sx = btn.i, sy = btn.j, dx = 0, dy = 0;     if( sx == 0 || sx == brdSize - 1 ) dx = sx == 0 ? 1 : - 1;    else if( sy == 0 || sy == brdSize - 1 ) dy = sy == 0 ? 1 : - 1;    var s = stepBeam( sx + dx, sy + dy, dx, dy );    switch( s.r ) {        case "H":             btn.innerHTML = "H";             updateScore( 1 );            break;        case "R":            btn.innerHTML = "R";            updateScore( 1 );            break;        case "O":            if( s.x == sx && s.y == sy ) {                btn.innerHTML = "R";                updateScore( 1 );            }            else {                var b = document.getElementById( "fire" + ( s.x + s.y * brdSize ) );                btn.innerHTML = "" + beamCnt;                b.innerHTML = "" + beamCnt;                beamCnt++;                updateScore( 2 );            }    }}function setAtom( btn ) {    if( done ) return;     var b = document.getElementById( "atom" + ( btn.i + btn.j * brdSize ) );    if( board[btn.i][btn.j].T == 0 && guesses < atoms ) {        board[btn.i][btn.j].T = 1;        guesses++;        b.innerHTML = "&#x2688;";    } else if( board[btn.i][btn.j].T == 1 && guesses > 0 ) {        board[btn.i][btn.j].T = 0;        guesses--;        b.innerHTML = " ";    }    if( guesses == atoms ) check.className = "check";    else check.className = "hide";}function startGame() {    score = 0;    updateScore();    check.className = again.className = "hide";    var e = document.getElementById( "mid" );    if( e.firstChild ) e.removeChild( e.firstChild );     brdSize = sel.value;    done = false;     if( brdSize < 5 ) return;     var brd = document.createElement( "div" );    brd.id = "board";    brd.style.height = brd.style.width = 5.2 * brdSize + "vh"    e.appendChild( brd );     var b, c, d;    for( var j = 0; j < brdSize; j++ ) {        for( var i = 0; i < brdSize; i++ ) {            b = document.createElement( "button" );            b.i = i; b.j = j;            if( j == 0 && i == 0 || j == 0 && i == brdSize - 1 ||                j == brdSize - 1 && i == 0 || j == brdSize - 1 && i == brdSize - 1 ) {                b.className = "corner";            } else {                if( j == 0 || j == brdSize - 1 || i == 0 || i == brdSize - 1 ) {                    b.className = "fire";                    b.id = "fire" + ( i + j * brdSize );                } else {                    b.className = "atom";                    b.id = "atom" + ( i + j * brdSize );                }                b.addEventListener( "click",                     function( e ) {                        if( e.target.className == "fire" && e.target.innerHTML == " " ) fireBeam( e.target );                        else if( e.target.className == "atom" ) setAtom( e.target );                    }, false );            }            b.appendChild( document.createTextNode( " " ) );            brd.appendChild( b );        }    }     board = new Array( brdSize );    for( var j = 0; j < brdSize; j++ ) {        board[j] = new Array( brdSize );        for( i = 0; i < brdSize; i++ ) {            board[j][i] = {H: 0, T: 0};        }    }     guesses = 0; beamCnt = 1;    atoms = brdSize == 7 ? 3 : brdSize == 10 ? 4 : 4 + Math.floor( Math.random() * 5 );     var s = brdSize - 2, i, j;    for( var k = 0; k < atoms; k++ ) {        while( true ) {            i = 1 + Math.floor( Math.random() * s );            j = 1 + Math.floor( Math.random() * s );            if( board[i][j].H == 0 ) break;        }        board[i][j].H = 1;    }}function init() {    sel = document.createElement( "select");    sel.options.add( new Option( "5 x 5 [3 atoms]", 7 ) );    sel.options.add( new Option( "8 x 8 [4 atoms]", 10 ) );    sel.options.add( new Option( "10 x 10 [4 - 8 atoms]", 12 ) );    sel.addEventListener( "change", startGame, false );    document.getElementById( "top" ).appendChild( sel );     check = document.createElement( "button" );    check.appendChild( document.createTextNode( "Check it!" ) );    check.className = "hide";    check.addEventListener( "click", checkIt, false );     again = document.createElement( "button" );    again.appendChild( document.createTextNode( "Again" ) );    again.className = "hide";    again.addEventListener( "click", startGame, false );     para = document.createElement( "p" );    para.className = "txt";    var d = document.getElementById( "bot" );     d.appendChild( para );    d.appendChild( check );    d.appendChild( again );    startGame();} `

## Julia

Gtk library GUI version.

`using Colors, Cairo, Graphics, Gtk struct BoxPosition    x::Int    y::Int    BoxPosition(i = 0, j = 0) = new(i, j)end @enum TrialResult Miss Hit Reflect Detour struct TrialBeam    entry::BoxPosition    exit::Union{BoxPosition, Nothing}    result::TrialResultend function blackboxapp(boxlength=8, boxwidth=8, numballs=4)    r, turncount, guesses, guesscount, correctguesses = 20, 0, BoxPosition[], 0, 0    showballs, boxoffsetx, boxoffsety = false, r, r    boxes = fill(colorant"wheat", boxlength + 4, boxwidth + 4)    beamhistory, ballpositions = Vector{TrialBeam}(), Vector{BoxPosition}()    win = GtkWindow("Black Box Game", 348, 800) |> (GtkFrame() |> (box = GtkBox(:v)))    settingsbox = GtkBox(:v)    playtoolbar = GtkToolbar()     newgame = GtkToolButton("New Game")    set_gtk_property!(newgame, :label, "New Game")    set_gtk_property!(newgame, :is_important, true)     reveal = GtkToolButton("Reveal")    set_gtk_property!(reveal, :label, "Reveal Box")    set_gtk_property!(reveal, :is_important, true)     map(w->push!(playtoolbar, w),[newgame, reveal])     scrwin = GtkScrolledWindow()    can = GtkCanvas()    set_gtk_property!(can, :expand, true)    map(w -> push!(box, w),[settingsbox, playtoolbar, scrwin])    push!(scrwin, can)     function newgame!(w)        empty!(ballpositions)        empty!(guesses)        empty!(beamhistory)        guessing, showballs, guesscount, correctguesses = false, false, 0, 0        fill!(boxes, colorant"wheat")        boxes[2, 3:end-2] .= boxes[end-1, 3:end-2] .= colorant"red"        boxes[3:end-2, 2] .= boxes[3:end-2, end-1] .= colorant"red"        boxes[3:end-2, 3:end-2] .= colorant"black"        while length(ballpositions) < numballs            p = BoxPosition(rand(3:boxlength+2), rand(3:boxwidth+2))            if !(p in ballpositions)                push!(ballpositions, p)            end        end        draw(can)    end     @guarded draw(can) do widget        ctx = Gtk.getgc(can)        select_font_face(ctx, "Courier", Cairo.FONT_SLANT_NORMAL, Cairo.FONT_WEIGHT_BOLD)        fontpointsize = 12        set_font_size(ctx, fontpointsize)        # print black box graphic        for i in 1:boxlength + 4, j in 1:boxwidth + 4            set_source(ctx, boxes[i, j])            move_to(ctx, boxoffsetx + i * r, boxoffsety + j * r)            rectangle(ctx, boxoffsetx + i * r, boxoffsety + j * r, r, r)            fill(ctx)            p = BoxPosition(i, j)            # show current guesses            if p in guesses                set_source(ctx, colorant"red")                move_to(ctx, boxoffsetx + i * r + 2, boxoffsety + j * r + fontpointsize)                show_text(ctx, p in ballpositions ? "+" : "-")                stroke(ctx)            end            # show ball placements if reveal -> showballs            if showballs && p in ballpositions                set_source(ctx, colorant"green")                circle(ctx, boxoffsetx + (i + 0.5) * r , boxoffsety + (j + 0.5) * r, 0.4 * r)                fill(ctx)            end        end        # draw dividing lines        set_line_width(ctx, 2)        set_source(ctx, colorant"wheat")        for i in 4:boxlength + 2            move_to(ctx, boxoffsetx + i * r, boxoffsety + 3 * r)            line_to(ctx, boxoffsetx + i * r, boxoffsety + (boxlength + 3) * r)            stroke(ctx)        end        for j in 4:boxwidth + 2            move_to(ctx, boxoffsetx + 3 * r, boxoffsety + j * r)            line_to(ctx, boxoffsetx + (boxlength + 3) * r, boxoffsety + j * r)            stroke(ctx)        end        # show scoring update        set_source(ctx, colorant"white")        rectangle(ctx, 0, 305, 400, 50)        fill(ctx)        correct, incorrect = string(correctguesses), string(guesscount - correctguesses)        score = string(2 * correctguesses - guesscount)        set_source(ctx, colorant"black")        move_to(ctx, 0, 320)        show_text(ctx, " Correct: \$correct  Incorrect: \$incorrect  Score: \$score")        stroke(ctx)        # show latest trial beams and results and trial history        set_source(ctx, colorant"white")        rectangle(ctx, 0, 360, 400, 420)        fill(ctx)        set_source(ctx, colorant"black")        move_to(ctx, 0, 360)        show_text(ctx, "      Test Beam History")        stroke(ctx)        move_to(ctx, 0, 360 + fontpointsize * 1.5)        show_text(ctx, " #  Start   Result      End")        stroke(ctx)        for (i, p) in enumerate(beamhistory)            move_to(ctx, 0, 360 + fontpointsize * (i + 1.5))            set_source(ctx, colorant"black")            s = " " * rpad(i, 3) * rpad("(\$(p.entry.x - 2),\$(p.entry.y - 2))", 8) *                 rpad(p.result, 12) * (p.exit == nothing ? " " :                     "(\$(p.exit.x - 2), \$(p.exit.y - 2))")            show_text(ctx, s)            stroke(ctx)            move_to(ctx, graphicxyfrombox(p.entry, 0.5 * fontpointsize)...)            set_source(ctx, colorant"yellow")            show_text(ctx, string(i))            stroke(ctx)            if p.exit != nothing                move_to(ctx, graphicxyfrombox(p.exit, 0.5 * fontpointsize)...)                set_source(ctx, colorant"lightblue")                show_text(ctx, string(i))                stroke(ctx)            end        end        Gtk.showall(win)    end     reveal!(w) = (showballs = !showballs; draw(can); Gtk.showall(win))    boxfromgraphicxy(x, y) = Int(round(x / r - 1.5)), Int(round(y / r - 1.5))    graphicxyfrombox(p, oset) = boxoffsetx + p.x * r + oset/2, boxoffsety + p.y * r + oset * 2    dirnext(x, y, dir) = x + dir[1], y + dir[2]    rightward(d) = (-d[2], d[1])    leftward(d) = (d[2], -d[1])    rearward(direction) = (-direction[1], -direction[2])    ballfront(x, y, d) = BoxPosition(x + d[1], y + d[2]) in ballpositions    ballright(x, y, d) = BoxPosition((dirnext(x, y, d) .+ rightward(d))...) in ballpositions    ballleft(x, y, d) = BoxPosition((dirnext(x, y, d) .+ leftward(d))...) in ballpositions    twocorners(x, y, d) = !ballfront(x, y, d) && ballright(x, y, d) && ballleft(x, y, d)    enteringstartzone(x, y, direction) = atstart(dirnext(x, y, direction)...)     function atstart(x, y)        return ((x == 2 || x == boxlength + 3) && (2 < y <= boxwidth + 3)) ||               ((y == 2 || y == boxwidth + 3) && (2 < x <= boxlength + 3))    end     function runpath(x, y)        startp = BoxPosition(x, y)        direction = (x == 2) ? (1, 0) : (x == boxlength + 3) ? (-1, 0) :                    (y == 2) ? (0, 1) : (0, -1)        while true            if ballfront(x, y, direction)                return Hit, nothing            elseif twocorners(x, y, direction)                if atstart(x, y)                    return Reflect, startp                end                direction = rearward(direction)                continue            elseif ballleft(x, y, direction)                if atstart(x, y)                    return Reflect, startp                end                direction = rightward(direction)                continue            elseif ballright(x, y, direction)                if atstart(x, y)                    return Reflect, startp                end                direction = leftward(direction)                continue            elseif enteringstartzone(x, y, direction)                x2, y2 = dirnext(x, y, direction)                endp = BoxPosition(x2, y2)                if x2 == startp.x && y2 == startp.y                    return Reflect, endp                else                    if startp.x == x2 ||  startp.y == y2                        return Miss, endp                    else                        return Detour, endp                    end                end            end            x, y = dirnext(x, y, direction)            @assert((2 < x < boxlength + 3) && (2 < y < boxwidth + 3))        end    end     can.mouse.button1press = @guarded (widget, event) -> begin        x, y = boxfromgraphicxy(event.x, event.y)        # get click in blackbox area as a guess        if 2 < x < boxlength + 3 && 2 < y < boxwidth + 3            p = BoxPosition(x, y)            if !(p in guesses)                push!(guesses, BoxPosition(x, y))                guesscount += 1                if p in ballpositions                    correctguesses += 1                end            end            draw(can)        # test beam        elseif atstart(x, y)            result, endpoint = runpath(x, y)            push!(beamhistory, TrialBeam(BoxPosition(x, y), endpoint, result))            if length(beamhistory) > 32                popfirst!(beamhistory)            end            draw(can)        end    end     condition = Condition()    endit(w) = notify(condition)    signal_connect(endit, win, :destroy)    signal_connect(newgame!, newgame, :clicked)    signal_connect(reveal!, reveal, :clicked)     newgame!(win)    Gtk.showall(win)    wait(condition)end blackboxapp() `

## Nim

Translation of: Go
`import random, sequtils, strutils const WikiGame = true type   Game = object    b: array[100, char]   # displayed board.    h: array[100, char]   # hidden atoms.  proc hideAtoms(game: var Game) =  var placed = 0  while placed < 4:    let a = rand(11..88)    let m = a mod 10    if m == 0 or m == 9 or game.h[a] == 'T':      continue    game.h[a] = 'T'    inc placed  proc initGame(): Game =  for i in 0..99:    result.b[i] = ' '    result.h[i] = 'F'  if not WikiGame:    result.hideAtoms()  else:    result.h[32] = 'T'    result.h[37] = 'T'    result.h[64] = 'T'    result.h[87] = 'T'  proc drawGrid(game: Game; score, guesses: Natural) =  echo "      0   1   2   3   4   5   6   7   8   9\n"  echo "        ╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗"  echo "a     \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$#".format(game.b[0..9].mapIt(\$it))  echo "    ╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗"  echo "b   ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║".format(game.b[10..19].mapIt(\$it))  echo "    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣"  echo "c   ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║".format(game.b[20..29].mapIt(\$it))  echo "    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣"  echo "d   ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║".format(game.b[30..39].mapIt(\$it))  echo "    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣"  echo "e   ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║".format(game.b[40..49].mapIt(\$it))  echo "    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣"  echo "f   ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║".format(game.b[50..59].mapIt(\$it))  echo "    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣"  echo "g   ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║".format(game.b[60..69].mapIt(\$it))  echo "    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣"  echo "h   ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║".format(game.b[70..79].mapIt(\$it))  echo "    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣"  echo "i   ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║".format(game.b[80..89].mapIt(\$it))  echo "    ╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝"  echo "j     \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$# ║ \$#".format(game.b[90..99].mapIt(\$it))  echo "        ╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝"   let status = if guesses == 4: "Game over!" else: "In play"  echo "\n        Score = ", score, "\tGuesses = ", guesses, "\t Status = ", status, '\n'  proc finalScore(game: var Game; score, guesses: Natural) =  var score = score  for i in 11..88:    let m = i mod 10    if m in [0, 9]: continue    if game.b[i] == 'G':      if game.h[i] == 'T':        game.b[i] = 'Y'      else:        game.b[i] = 'N'        inc score, 5    elif game.b[i] == ' ' and game.h[i] == 'T':      game.b[i] = 'A'  game.drawGrid(score, guesses)  func atCorner(ix: int): bool = ix in [0, 9, 90, 99] func inRange(ix: int): bool = ix in 1..98 and ix notin [9, 90] func atTop(ix: int): bool = ix in 1..8 func atBottom(ix: int): bool = ix in 91..98 func atLeft(ix: int): bool = ix.inRange and ix mod 10 == 0 func atRight(ix: int): bool = ix.inRange and ix mod 10 == 9 func inMiddle(ix: int): bool =  ix.inRange and not (ix.atTop or ix.atBottom or ix.atLeft or ix.atRight)  proc nextCell(game: Game): int =  while true:    stdout.write "    Choose cell: "    stdout.flushFile()    try:      let sq = stdin.readLine().toLowerAscii      if sq == "q":        quit "Quitting.", QuitSuccess      if sq.len != 2 or sq[0] notin 'a'..'j' or sq[1] notin '0'..'9':        continue      result = int((ord(sq[0]) - ord('a')) * 10 + ord(sq[1]) - ord('0'))      if not result.atCorner: break    except EOFError:      echo()      quit "Encountered end of file. Quitting.", QuitFailure  echo()  proc play(game: var Game) =  var score, guesses = 0  var num = '0'   block outer:    while true:      block inner:        game.drawGrid(score, guesses)        let ix = game.nextCell()        if not ix.inMiddle and game.b[ix] != ' ':     # already processed.          continue        var incr, def: int        if ix.atTop:          (incr, def) = (10, 1)        elif ix.atBottom:          (incr, def) = (-10, 1)        elif ix.atLeft:          (incr, def) = (1, 10)        elif ix.atRight:          (incr, def) = (-1, 10)        else:          if game.b[ix] != 'G':            game.b[ix] = 'G'            inc guesses            if guesses == 4: break outer          else:            game.b[ix] = ' '            dec guesses          continue         var first = true        var x = ix + incr        while x.inMiddle:           if game.h[x] == 'T':            # Hit.            game.b[ix] = 'H'            inc score            first = false            break inner           if first and (x + def).inMiddle and game.h[x + def] == 'T' or                       (x - def).inMiddle and game.h[x - def] == 'T':            # Reflection.            game.b[ix] = 'R'            inc score            first = false            break inner           first = false          var y = x + incr - def          if y.inMiddle and game.h[y] == 'T':            # Deflection.            (incr, def) = if incr in [-1, 1]: (10, 1) else: (1, 10)           y = x + incr + def          if y.inMiddle and game.h[y] == 'T':            # Deflection or double deflection.            (incr, def) = if incr in [-1, 1]: (-10, 1) else: (-1, 10)           inc x, incr         num = if num != '9': succ(num) else: 'a'        if game.b[ix] == ' ': inc score        game.b[ix] = num        if x.inRange:          if ix == x:            game.b[ix] = 'R'          else:            if game.b[x] == ' ': inc score            game.b[x] = num   game.drawGrid(score, guesses)  game.finalScore(score, guesses)  proc main() =   randomize()  while true:    var game = initGame()    echo """    === BLACK BOX ===       H    Hit (scores 1)      R    Reflection (scores 1)      1-9, Detour (scores 2)      a-c  Detour for 10-12 (scores 2)      G    Guess (maximum 4)      Y    Correct guess      N    Incorrect guess (scores 5)      A    Unguessed atom       Cells are numbered a0 to j9.      Corner cells do nothing.      Use edge cells to fire beam.      Use middle cells to add/delete a guess.      Game ends automatically after 4 guesses.      Enter q to abort game at any time.    """     game.play()     while true:      stdout.write "    Play again (y/n): "      stdout.flushFile()      case stdin.readLine().toLowerAscii()      of "n": return      of "y": break main()`
Output:

Using same input as in Wren entry with `WikiGame = true`:

```    === BLACK BOX ===

H    Hit (scores 1)
R    Reflection (scores 1)
1-9, Detour (scores 2)
a-c  Detour for 10-12 (scores 2)
G    Guess (maximum 4)
Y    Correct guess
N    Incorrect guess (scores 5)
A    Unguessed atom

Cells are numbered a0 to j9.
Corner cells do nothing.
Use edge cells to fire beam.
Use middle cells to add/delete a guess.
Game ends automatically after 4 guesses.
Enter q to abort game at any time.

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║   ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 0	Guesses = 0	 Status = In play

Choose cell: b0

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║   ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 2	Guesses = 0	 Status = In play

Choose cell: c0

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 0	 Status = In play

Choose cell: d7

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║ G ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 1	 Status = In play

Choose cell: d4

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║ G ║   ║   ║ G ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 2	 Status = In play

Choose cell: e3

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║ G ║   ║   ║ G ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║ G ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 3	 Status = In play

Choose cell: h2

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║ G ║   ║   ║ G ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║ G ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║ G ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 4	 Status = Game over!

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║ A ║   ║ N ║   ║   ║ Y ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║ N ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║ A ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║ N ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║ A ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 19	Guesses = 4	 Status = Game over!

Play again (y/n): n```

## Phix

Library: Phix/pGUI

A configurable GUI version of the Black Box game, with a Knuth solver/helper.

`-- demo\rosetta\Black_Box.exwconstant title = "Black Box",help_text = """Discover the location of objects/atoms using the fewest probes/rays. See distributed version for much longer help text and other comments."""integer size,           -- eg 8        s1, s2,         -- size+1|2        count,          -- eg 4        mask            -- eg #0b100000 (first such >size^2-count+1)                        -- Note that new_game() contains limiting code. sequence gameboard, -- actual, count 1's and size*size-count 0's.         eboard,    -- one of "", as being enumerated through         results,   -- results of rays/probes, {x,y,c,x,y} format         guessxy,   -- locations (each element is {x,y})         guessclr,  -- colours of "" (CD_BLUE for a guess,                    --                CD_GREEN for correct,                    --                CD_RED for wrong,                    --                CD_YELLOW/CYAN for hints.         hidden,    -- "" as saved during setup         possibles, -- up to 635,376 integer codes for 8*8 with 4 game,                    -- each entry being possible for content of results,                     -- but never deliberately driven over 100,000.         knowns,    -- these "are" atoms (but "maybe" if tried<maxtry)         minmaxmove -- best move available, see minmaxcount integer possible,   -- # of possibles checked to be plausible(), ie                    -- [posssible+1..\$] are all subject to imminent                    -- deletion by the idle handler, if invalid.        hinted,     -- # of probes analysed by hint_explore().        minmaxcount -- best (so far) atom tried, maxtry  -- # of enumerations attempted/theoretical max.bool hints_used = false -- (affects the scoring) function probe(integer x, y, sequence board, bool bSort=true)---- returns {x,y,c,rx,ry} primarily for use in redraw_cb(), and --                       secondarily for use in plausible().-- where c is: -1 for reflection, 0 for hit, and +1 otherwise.-- Note that for the latter you need to allocate an actual colour-- elsewhere (if this did that it would spanner plausible() etc),-- and also note that -2 is now in use for the ray/probe hint.-- Also x,y and rx,ry re-ordered lowest-first to avoid duplicates,-- except for hint exploration, which passes a bSort of false.--    integer rx = x, ry = y, -- current/emerge point (ray)            dx = 0, dy = 0, -- direction of travel            moves = 0       -- debug aid     if    x=0 then  dx = +1     -- left entry, moving right    elsif y=0 then  dy = +1     -- top        "		   down    elsif x=s1 then dx = -1     -- right      "		   left	    elsif y=s1 then dy = -1     -- btm        "			 up    else ?9/0 -- (sanity check)    end if     while true do         integer nx = rx+dx,     -- next logical position                ny = ry+dy,                idx = (ny-1)*size+nx         if nx=0 or nx=s1 or ny=0 or ny=s1 then            if x=nx and y=ny then                return {x,y,-1,0,0} -- Reflection            elsif bSort then                {{x,y},{nx,ny}} = sort({{x,y},{nx,ny}})            end if            return {x,y,1,nx,ny}    -- Emerges here        elsif idx<=0 then            ?9/0                    -- (sanity check)        elsif board[idx] then            return {x,y,0,0,0}      -- Hit        --        -- aside: rather than check diagonally, nx/ny are        --      simply discarded when a deflection occurs,        --      and we actually check things laterally.        --        elsif dx=0 then            -- up/down movement, check sides            if nx>1 and board[idx-1] then                if nx<size and board[idx+1] then                    dy = -dy            -- 180                else                    {dx,dy} = {1,0}     -- right                    -- (yep, both up & down deflected                    --  right by an atom on the left)                end if            elsif nx<size and board[idx+1] then                {dx,dy} = {-1,0}        -- left                --  (ditto left by one on the right)            else                {rx,ry} = {nx,ny}            end if        elsif dy=0 then            -- left/right movement, check above/below            if ny>1 and board[idx-size] then                if ny<size and board[idx+size] then                    dx = -dx            -- 180                else                    {dx,dy} = {0,1}     -- down                    -- (yep, left & right are both                    --  deflected down by one above)                end if            elsif ny<size and board[idx+size] then                {dx,dy} = {0,-1}        -- up                -- (ditto up by one below)            else                {rx,ry} = {nx,ny}            end if        else            ?9/0 -- (sanity check, dx,dy=={0,0}!?)        end if        if rx=0 or rx=s1 or ry=0 or ry=s1 then            {dx,dy} = {0,0} -- (outer swivel===reflection)        end if        -- guard against infinite loops, why not.        -- *2 because swivel/move counted separately.        moves += 1        if moves>2*size*size then ?9/0 end if    end while       end function function plausible(sequence board)    for i=1 to length(results) do        sequence ri = results[i]        integer {x,y} = ri        if probe(x,y,board)!=ri then return false end if    end for    return trueend function ---- For the smaller games we could use almost any storage method, but to facilitate larger -- boards with more atoms we should be as stingy with memory as possible. To that end an-- enumeration is stored as a compact set of offsets to the next piece. For instance the-- board {0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,....1} is stored as offsets {4,6,8,64-18}-- further using an appropriate mask to give (((((46*#40)+8)*#40)+6)*#40)+4 which can be-- stored as a single integer/atom, yet unpacked quite easily, see next. Note there is-- code in new_game(), for valuechanged_cb(), that ensures we can store count*bits, and-- more by luck than judgement that (partly) helps avoid configurations that would take-- far longer than the universe has existed to enumerate and scan even just the once.--function unpack(atom code)    sequence board = repeat(0,size*size)    integer offset = 0, r, check = 0    while code do        r = remainder(code,mask)        if r<=0 then ?9/0 end if        -- sanity check        offset += r        board[offset] = 1        code = floor(code/mask)        check += 1    end while    if check!=count then ?9/0 end if    -- sanity check    return boardend function function pack(sequence board)    atom code = 0, pmask = 1    integer idx = 0, check = 0    while true do        integer prev = idx        idx = find(1,board,idx+1)        if idx=0 then exit end if        code = code + (idx-prev)*pmask        check += 1        pmask *= mask    end while    if check!=count then ?9/0 end if    -- sanity check--  if unpack(code)!=board then ?9/0 end if -- ""    return codeend function procedure trim_possibles()---- Re-process the possibles table as follows:--  111...222322323...\$-- where 111... is possibly empty ok [1..possible],-- and 222322323 is some chunk [possible+1..limit],-- with 2s for oks and 3s for now-failing entries,-- which gets processed in a right-to-left order,-- such that fails(3) get replaced from the (1)s,-- being careful to quit early on any overlap, and-- /or re-test same slot if the 111... exhausted.-- Finally, trim off the dead head of possibles[].-- The result is quite scrambled, but care we not.--    integer limit = min(possible+100_000,length(possibles)),            limit0 = limit,            kill = 1 -- (actually 1 over)    while limit>max(possible,kill-1) do        if not plausible(unpack(possibles[limit])) then            possibles[limit] = possibles[kill]            if kill<=possible then                limit -= 1            end if            kill += 1        else            limit -= 1        end if    end while    possibles = possibles[kill..\$]    possible = limit0-kill+1end procedure procedure enumerate()    atom limit = min(tried+100_000,maxtry)    while tried<limit and length(possibles)<100_000 do        tried += 1        if plausible(eboard) then            possibles &= pack(eboard)            possible += 1        end if        --        -- think abacus: find the first bead you can shift left,        --                and slam the rest of them hard right.        -- similar to binary counting, but you must always have        --                exactly 'count' beads (ie 1's), eg        -- choose(2*2,2) is 6:        --       0b0011  0b0101  0b0110  0b1001  0b1010  0b1100        --        -- However, because we are scanning from top left down        -- to bottom right, it turned out better to do them in        -- reverse order, hence shift right and slam left (not        -- quite an exact mirror, but close enough).        --        integer idx = find(1,eboard), last = 1        while true do            eboard[idx] = 0            idx += 1            if idx>size*size then exit end if            if eboard[idx]=0 then                 eboard[idx] = 1                exit            end if            eboard[last] = 1            last += 1        end while        if idx=0 then exit end if    end whileend procedure function idx_from_edge(integer x,y)-- convert {x,y}, where one but not both of x,y are either 0 -- or s1, and the other is strictly 1..size, into 1..4*size.--  if x=0 then x = 0  -- (logically, but obvs. pointless)    if x=s1 then x = size    elsif y=0 then y = size*2    elsif y=s1 then y = size*3    elsif x!=0 then ?9/0 end if -- not an edge?!    return x+yend function function edge_from_idx(integer xy)-- convert 1..4*size into {0,1..size}/{s1,1..size}/{1..size,0}/{1..size,s1}    sequence res    integer c = floor((xy-1)/size)    switch c do        case 0: res = {0,xy}        case 1: res = {s1,xy-size}        case 2: res = {xy-size*2,0}        case 3: res = {xy-size*3,s1}        default: ?9/0    end switch    return resend function -- this is currently inlined, in case you were looking for it:--procedure idx_from_x_y(integer x, y)-- convert {1,1}..{size,size} to 1..size*size, for flat indexing--  return (y-1)*size+x--end function function x_y_from_idx(integer idx)-- convert 1..size*size to {1,1}..{size,size}-- (absence of floor() on /size is a deliberate sanity check)    integer x = remainder(idx-1,size)+1,            y = (idx-x)/size + 1    return {x,y}end function function next_hint()    sequence edges = repeat(0,size*4)    integer x,y,r    for i=1 to length(results) do        {x,y,r} = results[i]        for j=1 to 1+(r==1) do            integer idx = idx_from_edge(x,y)            if edges[idx] then ?9/0 end if            edges[idx] = 1            {?,?,?,x,y} = results[i]        end for    end for    integer new_hinted = find(0,edges,hinted+1)    return new_hintedend function procedure explore_hints(integer new_hinted)    if new_hinted then        -- originally, it proved better to scan these backwards...        -- it now breaks (wrong tiles, I guess) if not flipped...        new_hinted = size*4+1-new_hinted        integer {x,y} = edge_from_idx(new_hinted), k        sequence rxy = {}, counts = {}        for i=1 to possible do            sequence p = probe(x,y,unpack(possibles[i]),false)            k = find(p,rxy)            if k=0 then                rxy = append(rxy,p)                counts = append(counts,1)            else                counts[k] += 1            end if        end for        k = max(counts)        if hinted=0        or minmaxcount=0        or k<minmaxcount then            minmaxcount = k            k = maxsq(counts,true)            minmaxmove = rxy[k]            minmaxmove[3] = -2        end if        new_hinted = size*4+1-new_hinted  -- unflip        hinted = new_hinted    else        hinted = size*4    end ifend procedure procedure find_common()    sequence all = repeat(1,size*size),             none = repeat(0,size*size)    for i=1 to possible do        all = sq_and(all,unpack(possibles[i]))        if all==none then exit end if    end for    knowns = {}    for i=1 to length(all) do        if all[i] then            knowns = append(knowns,x_y_from_idx(i))        end if    end forend procedure include pGUI.eIhandle dlg, game_canvas, gridsize, atoms, score, hints, debug,         progress, declare constant colour_table = {CD_RED,                         CD_LIGHT_GREEN,                         CD_YELLOW,                         CD_BLUE,                         CD_ORANGE,                         CD_PURPLE,                         CD_CYAN,                         CD_MAGENTA,                         CD_GREEN,                         CD_DARK_GREEN,                         #bfef45,   -- Lime                         #fabebe,   -- Pink                         #469990,   -- Teal                         #e6beff,   -- Lavender                         #9A6324,   -- Brown                         #fffac8,   -- Beige                         #800000,   -- Maroon                         #aaffc3,   -- Mint                         #808000,   -- Olive                         #ffd8b1,   -- Apricot                         #000075}   -- Navy function colour(integer c)    c = mod(c-1,length(colour_table))+1    return colour_table[c]end function constant CD_HINTS = CD_DARK_GREY,   -- (where to fire probe)         CD_MAYBE = CD_YELLOW,      -- (probably an atom [scan not yet finished])         CD_KNOWN = CD_CYAN         -- (known atoms [scan finished]) procedure redraw()    IupUpdate(game_canvas)end procedure function idle_action()    integer new_hinted = 0    if possible<length(possibles) then          trim_possibles()        hinted = 0    elsif tried<maxtry and length(possibles)<100_000 then        enumerate()        hinted = 0    elsif IupGetInt(hints,"VALUE")      and hinted<size*4 then        if possible>1         and hinted<size*4 then            new_hinted = next_hint()            explore_hints(new_hinted)            redraw()        end if        if possible=1        or hinted=size*4 then            hinted = size*4            find_common()            redraw()        end if    else        return IUP_IGNORE -- (disables idle)    end if    string title = sprintf("%,d / %,d (%d%%)",{possible,tried,100*(tried/maxtry)})    if new_hinted then        title &= sprintf(", move %d/%d",{new_hinted,size*4})    end if    IupSetStrAttribute(progress,"TITLE",title)    return IUP_DEFAULTend functionconstant idle_action_cb = Icallback("idle_action") procedure start_idle()    IupSetAttribute(progress,"TITLE","-")    IupSetGlobalFunction("IDLE_ACTION",idle_action_cb)end procedure procedure new_game()    size = IupGetInt(gridsize,"VALUE")    s1 = size+1    s2 = size+2    count = IupGetInt(atoms,"VALUE")    while true do -- in case count too big        mask = #02        integer bits = 1        while mask<=size*size-count+1 do mask*=2 bits+=1 end while        --        -- Prevent overflow: must be able to store count*bits in a Phix atom.        -- count limits are therefore 13 on 5x5, 7 on 10x10, and 5 on 20x20,        -- on 32-bit, but 64-bit does 16 on 5x5, 9 on 10x10, and 7 on 20x20.        -- Many if not all of the silly-sized games this prohibits could not         -- possibly be fully analysed within a typical human lifespan anyway.        -- Besides just 5 atoms allows ambiguous/therefore unplayable games.        -- See also the comments before unpack() above. Trying to store too        -- many bits would trigger the sanity checks in pack()/unpack().        --        integer mb = iff(machine_bits()=32?53:64),                maxcount = min(floor(mb/bits),size*size)        if count<=maxcount then exit end if        count = maxcount        IupSetInt(atoms,"VALUE",count)    end while     eboard = repeat(0,size*size)    eboard[1..count] = 1    tried = 0    maxtry = choose(size*size,count)    possibles = {}    possible = 0    results = {}    guessxy = {}    guessclr = {}    hidden = {}    knowns = {}    minmaxcount = 0    gameboard = repeat(0,size*size)    bool active = IupGetInt(debug,"VALUE")    integer done = 0, x, y, xy    while done<count do        x = rand(size)        y = rand(size)        xy = (y-1)*size+x        if gameboard[xy]=0 then            gameboard[xy] = 1            hidden = append(hidden,{x,y})            done += 1        elsif not find(0,gameboard) then            ?9/0 -- let's not loop forever!                 -- (should now be prevented by maxcount above)        end if    end while    IupSetInt(declare, "ACTIVE", active)    if active then        guessxy = hidden        guessclr = repeat(CD_BLUE,length(guessxy))    end if    hints_used = (IupGetInt(hints,"VALUE") and not active)    start_idle()end procedure -- saved in redraw_cb(), for click testing in button_cb():integer wh, -- width and height        mx, my  -- margins -- saved in declare_cb(), for adding to the score (10 each)integer wrong = 0 function redraw_cb(Ihandle ih, integer /*posx*/, integer /*posy*/)    integer {w,h} = IupGetIntInt(ih, "DRAWSIZE")    -- calc width/height and margins (saved for button_cb):    wh = min(floor((w-10)/s2),floor((h-10)/s2))    mx = floor((w-wh*(s2))/2)    my = floor((h-wh*(s2))/2)     cdCanvas cddbuffer = IupGetAttributePtr(ih,"DBUFFER")    IupGLMakeCurrent(ih)    cdCanvasActivate(cddbuffer)    cdCanvasClear(cddbuffer)     -- outer edges (using one huge '+' shape)       cdCanvasSetForeground(cddbuffer,CD_GREY)    cdCanvasBox(cddbuffer,mx+wh,mx+wh*s1,my,my+wh*s2)    cdCanvasBox(cddbuffer,mx,mx+wh*s2,my+wh,my+wh*s1)    -- the inner size*size board (square)    cdCanvasSetForeground(cddbuffer,CD_LIGHT_GREY)    cdCanvasBox(cddbuffer,mx+wh,mx+wh*s1,my+wh,my+wh*s1)    -- draw the grid lines    cdCanvasSetForeground(cddbuffer,CD_WHITE)    integer {lx,ly} = {mx,my}    for i=1 to size+1 do        lx += wh        ly += wh        cdCanvasLine(cddbuffer,lx,my,lx,my+wh*s2)        cdCanvasLine(cddbuffer,mx,ly,mx+wh*s2,ly)    end for     sequence edges = repeat(0,size*4)    integer x,y,c = 1, h2 = floor(wh/2), r,            rfrom = (minmaxcount==0 or IupGetInt(hints,"VALUE")=0)    for i=rfrom to length(results) do        {x,y,r} = iff(i=0?minmaxmove:results[i])        integer cb, ct        string txt        {txt,cb,ct} = iff(r=-2?{"+",CD_HINTS,CD_BLACK}:                      iff(r=-1?{"R",CD_WHITE,CD_BLACK}:                      iff(r==0?{"H",CD_BLACK,CD_WHITE}:                   {sprintf("%d",c),CD_GREY,colour(c)})))        for j=1 to 1+(r==1) do            cdCanvasSetForeground(cddbuffer,cb)            integer cx = mx+wh*x,                    cy = my+wh*(s1-y)            cdCanvasBox(cddbuffer,cx+1,cx+wh,cy+1,cy+wh)            cdCanvasSetForeground(cddbuffer,ct)            cdCanvasFont(cddbuffer, "Helvetica", CD_BOLD, h2)            cdCanvasText(cddbuffer, cx+h2, cy+h2, txt)            if i!=0 then                integer idx = idx_from_edge(x,y)                if edges[idx] then ?9/0 end if                edges[idx] = 1                if r=1 then                    {?,?,?,x,y} = results[i]                    c += (j=2)                end if            end if        end for    end for    sequence gxy = guessxy,             gclr = guessclr    if IupGetInt(hints,"VALUE") then        for i=1 to length(knowns) do            sequence ki = knowns[i]            if not find(ki,gxy) then                gxy = append(gxy,ki)                gclr = append(gclr,iff(tried<maxtry?CD_MAYBE:CD_KNOWN))            end if        end for    end if    for i=1 to length(gxy) do        {x,y} = gxy[i]        atom cx = mx+(x+0.5)*wh,             cy = my+(s1-y+0.5)*wh        r = floor(wh*4/5)        cdCanvasSetForeground(cddbuffer,gclr[i])        cdCanvasCircle(cddbuffer, cx, cy, r)    end for    cdCanvasFlush(cddbuffer)--  IupSetStrAttribute(score,"TITLE","%d",{iff(hints_used?9999:sum(edges)+wrong*10)})    IupSetStrAttribute(score,"TITLE","%d",{sum(edges)+wrong*10})    return IUP_DEFAULTend function function map_cb(Ihandle ih)    IupGLMakeCurrent(ih)    atom res = IupGetDouble(NULL, "SCREENDPI")/25.4    cdCanvas cddbuffer = cdCreateCanvas(CD_GL, "10x10 %g", {res})    IupSetAttributePtr(ih,"DBUFFER",cddbuffer)    cdCanvasSetBackground(cddbuffer, CD_PARCHMENT)    {} = cdCanvasTextAlignment(cddbuffer, CD_CENTER)    return IUP_DEFAULTend function function canvas_resize_cb(Ihandle canvas)    cdCanvas cddbuffer = IupGetAttributePtr(canvas,"DBUFFER")    integer {canvas_width, canvas_height} = IupGetIntInt(canvas, "DRAWSIZE")    atom res = IupGetDouble(NULL, "SCREENDPI")/25.4    cdCanvasSetAttribute(cddbuffer, "SIZE", "%dx%d %g", {canvas_width, canvas_height, res})    return IUP_DEFAULTend function function declare_cb(Ihandle /*declare*/)    sequence add_h = repeat(true,length(hidden))    wrong = max(0,count-length(guessxy))    for i=1 to length(guessxy) do        integer k = find(guessxy[i],hidden)        if k then            guessclr[i] = CD_GREEN            add_h[k] = false        else            guessclr[i] = CD_RED            wrong += 1        end if    end for    for i=1 to length(add_h) do        if add_h[i] then            guessxy = append(guessxy,hidden[i])            guessclr = append(guessclr,CD_BLUE)        end if    end for    IupSetAttribute(declare, "ACTIVE", "NO")    redraw()    return IUP_DEFAULTend function function button_cb(Ihandle canvas, integer button, pressed, x, y, atom /*pStatus*/)    Ihandle frame = IupGetParent(canvas)    string title = IupGetAttribute(frame,"TITLE")    if button=IUP_BUTTON1 and not pressed then      -- (left button released)        x = floor((x-mx)/wh)        y = floor((y-my)/wh)        -- obviously, an x/y of 0 means left/top,        --            whereas s1 means right/btm,        --            and 1..size(both) is inner.        bool outerx = (x>=0 and x<=s1),             outery = (y>=0 and y<=s1),             innerx = (x>=1 and x<=size),             innery = (y>=1 and y<=size)        if innerx and innery then            sequence guess = {x,y}            integer k = find(guess,guessxy)            if k then                guessxy[k..k] = {}                guessclr[k..k] = {}            else                guessxy = append(guessxy,guess)                guessclr = append(guessclr,CD_BLUE)            end if            bool bActive = (length(guessxy)==count)            IupSetInt(declare, "ACTIVE", bActive)            if IupGetInt(debug,"VALUE")            and length(guessxy)=count then                hidden = guessxy                gameboard = repeat(0,size*size)                for i=1 to count do                    {x,y} = hidden[i]                    integer xy = (y-1)*size+x                    gameboard[xy] = 1                end for                results = {}            end if            redraw()        elsif (outerx and innery)           or (outery and innerx) then            sequence r = probe(x,y,gameboard)            if not find(r,results) then                results = append(results,r)                possible = 0                start_idle()            end if            redraw()        end if    end if    return IUP_CONTINUEend function function new_game_cb(Ihandle /*ih*/)    new_game()    redraw()    return IUP_DEFAULTend function function exit_cb(Ihandle /*ih*/)    return IUP_CLOSEend function function help_cb(Ihandln /*ih*/)    IupMessage(title,help_text)    return IUP_DEFAULTend function function key_cb(Ihandle /*dlg*/, atom c)    if c=K_ESC then return IUP_CLOSE end if    if c=K_F1 then return help_cb(NULL) end if    if c='?' then        -- an old diagnostic that I kept in...        for i=1 to min(5,length(possibles)) do            sequence s = unpack(possibles[i])            for j=1 to size do                ?s[1..size]                s = s[size+1..\$]            end for            puts(1,"\n")        end for        possible = 0        start_idle()    end if    return IUP_CONTINUEend function function valuechanged_cb(Ihandle ih)    if ih=hints then        hints_used = true        start_idle()    else        new_game()    end if    redraw()    return IUP_DEFAULTend functionconstant cb_valuechanged = Icallback("valuechanged_cb") procedure main()    IupOpen()     gridsize = IupText("SPIN=Yes, SPINMIN=1, SPINMAX=20, VALUE=8, RASTERSIZE=34x")    atoms = IupText("SPIN=Yes, SPINMIN=1, SPINMAX=16, VALUE=4, RASTERSIZE=34x")    score = IupLabel("","EXPAND=HORIZONTAL, PADDING=5x4")    hints = IupToggle("  Show Hints?","VALUE=YES, RIGHTBUTTON=YES, PADDING=5x4")    debug = IupToggle("Debug Mode?","VALUE=NO, RIGHTBUTTON=YES, PADDING=5x4")    progress = IupLabel("-","EXPAND=HORIZONTAL, PADDING=5x4")    declare = IupButton("Declare",Icallback("declare_cb"),"PADDING=5x4, ACTIVE=NO")    game_canvas = IupGLCanvas("RASTERSIZE=400x400")    Ihandle newgame = IupButton("New Game",Icallback("new_game_cb"),"PADDING=5x4"),            help = IupButton("Help (F1)",Icallback("help_cb"),"PADDING=5x4"),            quit = IupButton("E&xit",Icallback("exit_cb"),"PADDING=5x4"),            vbox = IupVbox({IupHbox({IupLabel("Size","PADDING=5x4"),gridsize,                                     IupFill(),                                     IupLabel("Atoms","PADDING=5x4"),atoms}),                            IupHbox({hints,IupFill(),debug}),                            IupHbox({progress}),                            IupHbox({IupLabel("Score","PADDING=5x4"),score}),                            IupHbox({declare,newgame,help,quit})},"MARGIN=5x5"),            game_frame = IupFrame(IupHbox({game_canvas},"MARGIN=3x3"),"TITLE=Game"),            option_frame = IupFrame(vbox,"TITLE=Options"),            full = IupHbox({game_frame,option_frame})    IupSetCallbacks({gridsize,atoms,hints,debug}, {"VALUECHANGED_CB", cb_valuechanged})    IupSetCallbacks(game_canvas, {"ACTION", Icallback("redraw_cb"),                                  "MAP_CB", Icallback("map_cb"),                                  "RESIZE_CB", Icallback("canvas_resize_cb"),                                  "BUTTON_CB", Icallback("button_cb")})    dlg = IupDialog(IupHbox({full},"MARGIN=3x3"))    IupSetAttribute(dlg, "TITLE", title)    IupSetCallback(dlg, "K_ANY", Icallback("key_cb"))    IupSetAttributeHandle(dlg,"DEFAULTENTER", declare)  --erm...??     new_game()     IupShowXY(dlg,IUP_CENTER,IUP_CENTER)    IupSetAttribute(dlg, "RASTERSIZE", NULL)    IupSetStrAttribute(dlg, "MINSIZE", IupGetAttribute(dlg,"RASTERSIZE"))    sequence fixsize = {score,progress}    for i=1 to length(fixsize) do        Ihandle fi = fixsize[i]        IupSetAttributes(fi, "RASTERSIZE=%s, EXPAND=NO", {IupGetAttribute(fi,"RASTERSIZE")})    end for    IupMainLoop()    IupClose()end procedure main()`

## Wren

Translation of: Go
Library: Wren-fmt
Library: Wren-ioutil
Library: Wren-str
`import "random" for Randomimport "/fmt" for Fmtimport "/ioutil" for Inputimport "/str" for Str  var b = List.filled(100, null)  // displayed boardvar h = List.filled(100, null)  // hidden atomsvar wikiGame = true             // set to false for a 'random' gamevar rand = Random.new() var hideAtoms = Fn.new {    var placed = 0    while (placed < 4) {        var a = rand.int(11, 89) // 11 to 88 inclusive        var m = a % 10        if (m == 0 || m == 9 || h[a] == "T") continue        h[a] = "T"        placed = placed + 1    }} var initialize = Fn.new {    for (i in 0..99) {        b[i] = " "        h[i] = "F"    }    if (!wikiGame) {        hideAtoms.call()    } else {        h[32] = "T"        h[37] = "T"        h[64] = "T"        h[87] = "T"    }    System.print("""    === BLACK BOX ===     H    Hit (scores 1)    R    Reflection (scores 1)    1-9, Detour (scores 2)    a-c  Detour for 10-12 (scores 2)    G    Guess (maximum 4)    Y    Correct guess    N    Incorrect guess (scores 5)    A    Unguessed atom     Cells are numbered a0 to j9.    Corner cells do nothing.    Use edge cells to fire beam.    Use middle cells to add/delete a guess.    Game ends automatically after 4 guesses.    Enter q to abort game at any time.    """)} var drawGrid = Fn.new { |score, guesses|    System.print("      0   1   2   3   4   5   6   7   8   9 ")    System.print()    System.print("        ╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗")    Fmt.lprint("a     \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s",        [b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9]])    System.print("    ╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗")    Fmt.lprint  ("b   ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║",        [b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]])    System.print("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣")    Fmt.lprint  ("c   ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║",        [b[20], b[21], b[22], b[23], b[24], b[25], b[26], b[27], b[28], b[29]])    System.print("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣")    Fmt.lprint  ("d   ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║",        [b[30], b[31], b[32], b[33], b[34], b[35], b[36], b[37], b[38], b[39]])    System.print("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣")    Fmt.lprint  ("e   ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║",        [b[40], b[41], b[42], b[43], b[44], b[45], b[46], b[47], b[48], b[49]])    System.print("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣")    Fmt.lprint  ("f   ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║",        [b[50], b[51], b[52], b[53], b[54], b[55], b[56], b[57], b[58], b[59]])    System.print("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣")    Fmt.lprint  ("g   ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║",        [b[60], b[61], b[62], b[63], b[64], b[65], b[66], b[67], b[68], b[69]])    System.print("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣")    Fmt.lprint  ("h   ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║",        [b[70], b[71], b[72], b[73], b[74], b[75], b[76], b[77], b[78], b[79]])    System.print("    ╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣")    Fmt.lprint  ("i   ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║",        [b[80], b[81], b[82], b[83], b[84], b[85], b[86], b[87], b[88], b[89]])    System.print("    ╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝")    Fmt.lprint  ("j     \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s ║ \$s",        [b[90], b[91], b[92], b[93], b[94], b[95], b[96], b[97], b[98], b[99]])    System.print("        ╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝")    var status = (guesses != 4) ? "In play" : "Game over!"    System.print("\n        Score = %(score)\tGuesses = %(guesses)\t Status = %(status)\n")} var atCorner = Fn.new { |ix| ix == 0 || ix == 9 || ix == 90 || ix == 99 } var inRange  = Fn.new { |ix| ix >= 1 && ix <= 98 && ix != 9 && ix != 90 } var atTop    = Fn.new { |ix| ix >= 1 && ix <= 8 } var atBottom = Fn.new { |ix| ix >= 91 && ix <= 98 } var atLeft   = Fn.new { |ix| inRange.call(ix) && ix%10 == 0 } var atRight  = Fn.new { |ix| inRange.call(ix) && ix%10 == 9 } var inMiddle = Fn.new { |ix|    return inRange.call(ix) && !atTop.call(ix) && !atBottom.call(ix) &&           !atLeft.call(ix) && !atRight.call(ix)} var nextCell = Fn.new {    var ix    while (true) {        var sq = Str.lower(Input.text("    Choose cell : ", 1))        if (sq.count == 1 && sq[0] == "q") {            Fiber.abort("program aborted")        }        if (sq.count != 2 || !"abcdefghij".contains(sq[0]) || !"0123456789".contains(sq[1])) {            continue        }        ix = (sq[0].bytes[0] - 97) * 10 + sq[1].bytes[0] - 48        if (atCorner.call(ix)) continue        break    }    System.print()    return ix} var finalScore = Fn.new { |score, guesses|    for (i in 11..88) {        var m = i % 10        if (m == 0 || m == 9) continue        if (b[i] == "G" && h[i] == "T") {            b[i] = "Y"        } else if (b[i] == "G" && h[i] == "F") {            b[i] = "N"            score = score + 5        } else if (b[i] == " " && h[i] == "T") {            b[i] = "A"        }    }    drawGrid.call(score, guesses)} var play = Fn.new {    var score = 0    var guesses = 0    var num = "0"    while (true) {        var outer = false        drawGrid.call(score, guesses)        var ix = nextCell.call()        if (!inMiddle.call(ix) && b[ix] != " ") continue  // already processed        var inc        var def        if (atTop.call(ix)) {            inc = 10            def = 1        } else if (atBottom.call(ix)) {            inc = -10            def = 1        } else if (atLeft.call(ix)) {            inc = 1            def = 10        } else if (atRight.call(ix)) {            inc = -1            def = 10        } else {            if (b[ix] != "G") {                b[ix] = "G"                guesses = guesses + 1                if (guesses == 4) break            } else {                b[ix] = " "                guesses = guesses - 1            }            continue        }        var x = ix + inc        var first = true        while (inMiddle.call(x)) {            if (h[x] == "T" ) {  // hit                b[ix] = "H"                score = score + 1                first = false                outer = true                break            }            if (first && (inMiddle.call(x+def) && h[x+def] == "T") ||                (inMiddle.call(x-def) && h[x-def] == "T")) {  // reflection                b[ix] = "R"                score = score + 1                first = false                outer = true                break            }            first = false            var y = x + inc - def            if (inMiddle.call(y) && h[y] == "T") {  // deflection                if (inc.abs == 1) {                    inc = 10                    def = 1                } else if (inc.abs == 10) {                    inc = 1                    def = 10                }            }            y = x + inc + def            if (inMiddle.call(y) && h[y] == "T") {  // deflection or double deflection                if (inc.abs == 1) {                    inc = -10                    def = 1                } else if (inc.abs == 10) {                    inc = -1                    def = 10                }            }            x = x + inc        }        if (outer) continue        if (num != "9") {            num = String.fromByte(num.bytes[0] + 1)        } else {            num = "a"        }        if (b[ix] == " ") score = score + 1        b[ix] = num        if (inRange.call(x)) {            if (ix == x) {                b[ix] = "R"            } else {                if (b[x] == " ") score = score + 1                b[x] = num            }        }    }    drawGrid.call(score, guesses)    finalScore.call(score, guesses)} while (true) {    initialize.call()    play.call()    var yn = Str.lower(Input.option("    Play again y/n : ", "ynYN"))    if (yn == "n") return}`
Output:

Sample game (wikiGame == true):

```    === BLACK BOX ===

H    Hit (scores 1)
R    Reflection (scores 1)
1-9, Detour (scores 2)
a-c  Detour for 10-12 (scores 2)
G    Guess (maximum 4)
Y    Correct guess
N    Incorrect guess (scores 5)
A    Unguessed atom

Cells are numbered a0 to j9.
Corner cells do nothing.
Use edge cells to fire beam.
Use middle cells to add/delete a guess.
Game ends automatically after 4 guesses.
Enter q to abort game at any time.
0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║   ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 0	Guesses = 0	 Status = In play

Choose cell : b0

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║   ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 2	Guesses = 0	 Status = In play

Choose cell : c0

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 0	 Status = In play

Choose cell : d7

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║   ║   ║   ║ G ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 1	 Status = In play

Choose cell : d4

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║ G ║   ║   ║ G ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 2	 Status = In play

Choose cell : e3

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║ G ║   ║   ║ G ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║ G ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 3	 Status = In play

Choose cell : h2

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║   ║   ║ G ║   ║   ║ G ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║ G ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║ G ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 4	Guesses = 4	 Status = Game over!

0   1   2   3   4   5   6   7   8   9

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
a       ║ 2 ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b   ║ 1 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
c   ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
d   ║   ║   ║ A ║   ║ N ║   ║   ║ Y ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
e   ║   ║   ║   ║ N ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
f   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
g   ║   ║   ║   ║   ║ A ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
h   ║   ║   ║ N ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
i   ║   ║   ║   ║   ║   ║   ║   ║ A ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j       ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Score = 19	Guesses = 4	 Status = Game over!

Play again y/n : n
```

## zkl

Translation of: Go
`const ATM="A", F="F", HIT="H", G="G", GN="N", R="R", BLNK=" ", GY="Y"; var   brd,hdn,	    // displayed board & hidden atoms   wikiGame = True; // set to False for a 'random' game fcn initialize{   brd,hdn = List.createLong(100,BLNK), List.createLong(100,F);    if(not wikiGame) hideAtoms();   else hdn[32] = hdn[37] = hdn[64] = hdn[87] = ATM;//   else hdn[64] = hdn[66] = ATM;	// Double deflection case    println(#<<<"    === BLACK BOX ===     H    Hit (scores 1)    R    Reflection (scores 1)    1-9, Detour (scores 2)    a-c  Detour for 10-12 (scores 2)    G    Guess (maximum 4)    Y    Correct guess    N    Incorrect guess (scores 5)    A    Unguessed atom     Cells are numbered a0 to j9.    Corner cells do nothing.    Use edge cells to fire beam.    Use middle cells to add/delete a guess.    Game ends automatically after 4 guesses.    Enter q to abort game at any time.\n\n");#<<<} fcn drawGrid(score, guesses){   var [const] vbs="\u2550\u2550\u2550\u256c", bt=(vbs.del(-3,3)),      be1=String("      %s",vbs*7,bt,"%s").fmt,      b1=be1("\u2554","\u2557"), e1=be1("\u255a","\u255d"),       be2=String("  %s", vbs*9, bt,"%s").fmt,      b2=be2("\u2554", "\u2557"), b3=be2("\u256c", "\u256c"),       e2=be2("\u255a", "\u255d"),       g1=String("%s%s    ","\u2551 %s "*9).fmt,		// a brd[0]=brd[90]=" "      g2=String("%s ","\u2551 %s "*11).del(-3,3).fmt;	// b c d .. i    println("    0   1   2   3   4   5   6   7   8   9 \n",b1);   grid,sep,n := g1, b2, -10;   foreach c in (["a".."i"]){      println(grid(c,brd[n+=10,10].xplode()));      println((c=="i") and e2 or sep);      grid,sep = g2,b3;   }   println(g1("j",brd[90,10].xplode()), "\n", e1);    status:=(guesses==4) and "Game over!" or "In play";   println("\n        Score = ", score, "\tGuesses = ", guesses, "\t Status = ", status);} fcn hideAtoms{   n:=4; do{      a,m:=(11).random(89), a % 10; 	// 11 to 88 inclusive      if(m==0 or m==9 or hdn[a]==ATM) continue;      hdn[a]=ATM;      n-=1;   }while(n);} fcn nextCell{   while(True){      s,c,n,sz := ask("    Choose cell [a-j][0-9]: ").strip().toLower(), s[0,1], s[1,1], s.len();      if(sz==1 and c=="q") System.exit();      if(not (sz==2 and ("a"<=c<="j") and ("0"<=n<="9"))) continue;      ix:=10*(c.toAsc() - 97) + n;	// row major, "a"-'a'      if(not atCorner(ix)){ println(); return(ix); }   }} fcn atCorner(ix){  ix==0 or ix==9 or ix==90 or ix==99 }fcn inRange(ix) {  (1<=ix<=98) and ix!=9 and ix!=90 }fcn atTop(ix)   {   1<=ix<= 8 }fcn atBottom(ix){  91<=ix<=98 }	fcn atLeft(ix)  {  inRange(ix) and ix%10 ==0 }fcn atRight(ix) {  inRange(ix) and ix%10 ==9 }fcn inMiddle(ix){   inRange(ix) and not ( atTop(ix) or atBottom(ix) or atLeft(ix) or atRight(ix) )}fcn play{   score,guesses,num := 0,0, 0x30;	// '0'   while(True){      drawGrid(score, guesses);      ix:=nextCell();      if(not inMiddle(ix) and brd[ix]!=BLNK) continue; // already processed      inc,def := 0,0;      if     (atTop(ix))    inc,def =  10,  1;      else if(atBottom(ix)) inc,def = -10,  1;      else if(atLeft(ix))   inc,def =   1, 10;      else if(atRight(ix))  inc,def =  -1, 10;      else{	 if(brd[ix]!=G){	    brd[ix]=G;	    if( (guesses+=1) ==4) break(1);	// you done	 }else{ brd[ix]=BLNK; guesses-=1; }	 continue;      }      x,first := ix + inc, True;      while(inMiddle(x)){ 	 if(hdn[x]==ATM){					// hit	    brd[ix]=HIT;	    score+=1;	    first=False;	    continue(2);	 }	 if(first and (inMiddle(x + def) and hdn[x + def]==ATM) or	    (inMiddle(x - def) and hdn[x - def]==ATM)){		// reflection	    brd[ix]=R;	    score+=1;	    first=False;	    continue(2);	 }	 first=False;	 y:=x + inc - def;	 if(inMiddle(y) and hdn[y]==ATM){			// deflection	    switch(inc){	       case( 1,  -1){  inc, def = 10, 1 }	       case(10, -10){  inc, def =  1,10 }	    }	 }	 y=x + inc + def;	 if(inMiddle(y) and hdn[y]==ATM){    // deflection or double deflection	    switch(inc){	       case( 1,  -1){ inc, def = -10,  1 }	       case(10, -10){ inc, def =  -1, 10 }	    }	 }	 x+=inc;      }// while inMiddle       if(brd[ix]==BLNK) score+=1;      if(num!=0x39) num+=1; else num=97;	// '0' & 'a'      brd[ix]=num.toChar();			// right back at ya      if(inRange(x)){	 if(ix==x) brd[ix]=R;	 else{	    if(brd[x]==BLNK) score+=1;	    brd[x]=num.toChar();	 }      }   }   drawGrid(  score, guesses);   finalScore(score, guesses);} fcn finalScore(score, guesses){println(hdn.toString(*));   foreach i in ([11..88]){      m:=i%10;      if(m==0 or m==9)		  	    continue;      if(brd[i]==G and hdn[i]==ATM)         brd[i]=GY;      else if(brd[i]==G and hdn[i]==F){     brd[i]=GN; score+=5; }      else if(brd[i]==BLNK and hdn[i]==ATM) brd[i]=ATM;   }   drawGrid(score, guesses);} while(True){   initialize(); play();   while(True){      yn:=ask("    Play again y/n : ").strip().toLower();      if(yn=="n")      break(2);      else if(yn=="y") break(1);   }}`

Showing [results of] most of the Wikipedia actions:

Output:
```    === BLACK BOX ===

H    Hit (scores 1)
R    Reflection (scores 1)
1-9, Detour (scores 2)
a-c  Detour for 10-12 (scores 2)
G    Guess (maximum 4)
Y    Correct guess
N    Incorrect guess (scores 5)
A    Unguessed atom

Cells are numbered a0 to j9.
Corner cells do nothing.
Use edge cells to fire beam.
Use middle cells to add/delete a guess.
Game ends automatically after 4 guesses.
Enter q to abort game at any time.

0   1   2   3   4   5   6   7   8   9
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
a     ║   ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
c ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
d ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
e ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
f ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
g ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
h ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
i ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j     ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝

Score = 0	Guesses = 0	 Status = In play
Choose cell [a-j][0-9]: g9

0   1   2   3   4   5   6   7   8   9
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
a     ║   ║   ║   ║   ║   ║   ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
c ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
d ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
e ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
f ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
g ║   ║   ║   ║   ║   ║   ║   ║   ║   ║ H ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
h ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
i ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j     ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝

Score = 1	Guesses = 0	 Status = In play
...
Choose cell [a-j][0-9]: f0

0   1   2   3   4   5   6   7   8   9
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
a     ║   ║   ║ 3 ║   ║ 1 ║ 3 ║   ║   ║
╔═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╗
b ║ 2 ║   ║   ║   ║   ║   ║   ║   ║   ║ 2 ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
c ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
d ║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
e ║   ║   ║   ║   ║   ║   ║   ║   ║   ║ 4 ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
f ║ 5 ║   ║   ║   ║   ║   ║   ║   ║   ║ 1 ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
g ║   ║   ║   ║   ║   ║   ║   ║   ║   ║ H ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
h ║   ║   ║   ║   ║   ║   ║   ║   ║   ║ 4 ║
╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬
i ║   ║   ║   ║   ║   ║   ║ G ║   ║   ║   ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝
j     ║   ║   ║   ║   ║ 5 ║ R ║ H ║ R ║
╚═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╝

Score = 14	Guesses = 1	 Status = In play
```