Implement a version of the [https://en.wikipedia.org/wiki/Black_Box_(game) 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())
    }
}

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 [http://paulo-jorente.de/tests/blackbox/ 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();
}