Task: Tic-tac-toe




Go: package main

import (
    "bufio"
    "fmt"
    "math/rand"
    "os"
    "strings"
)

var b []byte

func printBoard() {
    fmt.Printf("%s\n%s\n%s\n", b[0:3], b[3:6], b[6:9])
}

var pScore, cScore int
var pMark, cMark byte = 'X', 'O'
var in = bufio.NewReader(os.Stdin)

func main() {
    b = make([]byte, 9)
    fmt.Println("Play by entering a digit.")
    for {
        
        for i := range b {
            b[i] = '1' + byte(i)
        }
        computerStart := cMark == 'X'
        if computerStart {
            fmt.Println("I go first, playing X's")
        } else {
            fmt.Println("You go first, playing X's")
        }
    TakeTurns:
        for {
            if !computerStart {
                if !playerTurn() {
                    return
                }
                if gameOver() {
                    break TakeTurns
                }

            }
            computerStart = false
            computerTurn()
            if gameOver() {
                break TakeTurns
            }
        }
        fmt.Println("Score: you", pScore, "me", cScore)
        fmt.Println("\nLet's play again.")
    }
}

func playerTurn() bool {
    var pm string
    var err error
    for i := 0; i < 3; i++ { 
        printBoard()
        fmt.Printf("%c's move? ", pMark)
        if pm, err = in.ReadString('\n'); err != nil {
            fmt.Println(err)
            return false
        }
        pm = strings.TrimSpace(pm)
        if pm >= "1" && pm <= "9" && b[pm[0]-'1'] == pm[0] {
            x := pm[0] - '1'
            b[x] = pMark
            return true
        }
    }
    fmt.Println("You're not playing right.")
    return false
}

var choices = make([]int, 9)

func computerTurn() {
    printBoard()
    var x int
    defer func() {
        fmt.Println("My move:", x+1)
        b[x] = cMark
    }()
    
    block := -1
    for _, l := range lines {
        var mine, yours int
        x = -1
        for _, sq := range l {
            switch b[sq] {
            case cMark:
                mine++
            case pMark:
                yours++
            default:
                x = sq
            }
        }
        if mine == 2 && x >= 0 {
            return 
        }
        if yours == 2 && x >= 0 {
            block = x
        } 
    }
    if block >= 0 {
        x = block 
        return
    }
    
    choices = choices[:0]
    for i, sq := range b { 
        if sq == '1'+byte(i) {
            choices = append(choices, i)
        }
    }
    x = choices[rand.Intn(len(choices))]
}   
    
func gameOver() bool {
    
    for _, l := range lines {
        if b[l[0]] == b[l[1]] && b[l[1]] == b[l[2]] {
            printBoard()
            if b[l[0]] == cMark {
                fmt.Println("I win!")
                cScore++
                pMark, cMark = 'X', 'O'
            } else {
                fmt.Println("You win!")
                pScore++
                pMark, cMark = 'O', 'X'
            }
            return true 
        } 
    }
    
    for i, sq := range b {
        if sq == '1'+byte(i) {
            return false
        }
    }
    fmt.Println("Cat game.")
    pMark, cMark = cMark, pMark
    return true
}

var lines = [][]int{
    {0, 1, 2}, 
    {3, 4, 5},
    {6, 7, 8},
    {0, 3, 6}, 
    {1, 4, 7},
    {2, 5, 8},
    {0, 4, 8}, 
    {2, 4, 6},
}



PHP: <?php
const BOARD_NUM = 9;
const ROW_NUM = 3;
$EMPTY_BOARD_STR = str_repeat('.', BOARD_NUM);

function isGameOver($board, $pin) {
	$pat = 
		'/X{3}|' . //Horz
		'X..X..X..|' . //Vert Left
		'.X..X..X.|' . //Vert Middle
		'..X..X..X|' . //Vert Right
		'..X.X.X..|' . //Diag TL->BR
		'X...X...X|' . //Diag TR->BL
		'[^\.]{9}/i'; //Cat's game
	if ($pin == 'O') $pat = str_replace('X', 'O', $pat);
	return preg_match($pat, $board);
}

$boardStr = isset($_GET['b'])? $_GET['b'] : $EMPTY_BOARD_STR;
$turn = substr_count($boardStr, '.')%2==0? 'O' : 'X';
$oppTurn = $turn == 'X'? 'O' : 'X';
$gameOver = isGameOver($boardStr, $oppTurn);

echo '<style>';
echo 'td {width: 200px; height: 200px; text-align: center; }';
echo '.pin {font-size:72pt; text-decoration:none; color: black}';
echo '.pin.X {color:red}';
echo '.pin.O {color:blue}';
echo '</style>';
echo '<table border="1">';
$p = 0;
for ($r = 0; $r < ROW_NUM; $r++) {
	echo '<tr>';
	for ($c = 0; $c < ROW_NUM; $c++) {
		$pin = $boardStr[$p];
		
		echo '<td>';		
		if ($gameOver || $pin != '.') echo '<span class="pin ', $pin, '">', $pin, '</span>'; //Occupied
		else { //Available
			$boardDelta = $boardStr;
			$boardDelta[$p] = $turn;		
			echo '<a class="pin ', $pin, '" href="?b=', $boardDelta, '">';
			echo $boardStr[$p];
			echo '</a>';
		}
		
		echo '</td>';	
		$p++;
	}
	echo '</tr>';
	echo '<input type="hidden" name="b" value="', $boardStr, '"/>';
}
echo '</table>';
echo '<a href="?b=', $EMPTY_BOARD_STR, '">Reset</a>';
if ($gameOver) echo '<h1>Game Over!</h1>';