<?php
define("NOUGHT", 1);
define("CROSS", 2);
function isDone(&$step, $stepkey) {
global $wonmap;
for ($i = 0; $i < 3; $i++) {
// -
if ($step[0][$i]['player'] == $step[1][$i]['player'] &&
$step[0][$i]['player'] == $step[2][$i]['player'] &&
$step[0][$i]['player'] > 0) {
$wonmap[$stepkey] = "-$i";
return $step[0][$i]['player'];
}
// |
if ($step[$i][0]['player'] == $step[$i][1]['player'] &&
$step[$i][0]['player'] == $step[$i][2]['player'] &&
$step[$i][0]['player'] > 0) {
$wonmap[$stepkey] = "|$i";
return $step[$i][0]['player'];
}
}
// \
if ($step[0][0]['player'] == $step[1][1]['player'] &&
$step[0][0]['player'] == $step[2][2]['player'] &&
$step[0][0]['player'] > 0) {
$wonmap[$stepkey] = "\\";
return $step[0][0]['player'];
}
// /
if ($step[2][0]['player'] == $step[1][1]['player'] &&
$step[2][0]['player'] == $step[0][2]['player'] &&
$step[2][0]['player'] > 0) {
$wonmap[$stepkey] = "/";
return $step[2][0]['player'];
}
return 0;
}
function genkey($step) {
$str = "";
for ($y = 0; $y < 3; $y++) {
for ($x = 0; $x < 3; $x++) {
//$str .= $step[$x][$y]['player'].$step[$x][$y]['stepkey'];
$str .= $step[$x][$y]['player'];
}
}
return md5($str);
}
function create_step(...$cell) {
return array(
array($cell[0], $cell[1], $cell[2]),
array($cell[3], $cell[4], $cell[5]),
array($cell[6], $cell[7], $cell[8])
);
}
function create_steps(&$map, $currstepkey, $player, $level) {
$currstep = &$map[$currstepkey];
if (isDone($currstep, $currstepkey)) {
for ($y = 0; $y < 3; $y++) {
for ($x = 0; $x < 3; $x++) {
$currstep[$x][$y]['stepkey'] = $currstepkey;
}
}
return $currstepkey;
}
for ($y = 0; $y < 3; $y++) {
for ($x = 0; $x < 3; $x++) {
if ($currstep[$x][$y]['player'] > 0) {
$currstep[$x][$y]['stepkey'] = $currstepkey;
continue;
}
$newstep = create_step(...array_merge(...$currstep));
$newstep[$x][$y] = array('player' => $player, 'stepkey' => 0);
$newstepkey = genkey($newstep);
$currstep[$x][$y]['stepkey'] = $newstepkey;
$map[$newstepkey] = $newstep;
create_steps($map, $newstepkey, 3 - $player, $level + 1);
}
}
return $currstepkey;
}
$step0 = create_step(...array_fill(0, 9, array('player' => 0, 'stepkey' => 0)));
$step0key = genkey($step0);
$map = array($step0key => $step0);
$wonmap = array();
create_steps($map, $step0key, NOUGHT, 0);
// change long md5 id to short numeric keys
$shortids = array( 0 => 0);
$counter = 0;
foreach ($map as $stepkey => $step) {
$shortids[$stepkey] = $counter++;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
user-select: none
}
body > p {
margin: 0px;
display: none;
font-size: 60pt;
width: fit-content;
}
body > p > label {
box-sizing: border-box;
border: 1px solid black;
width: 100px;
height: 100px;
display: inline-block;
text-align: center;
background-color: yellow;
line-height: 1.2;
font-weight: 400;
}
body > p:has(> input:checked) {
display: block;
}
body > p > input {
display: none;
position: relative;
}
body > p > span {
position: absolute;
background-color: red;
height: 30px;
border-radius: 15px;
animation-duration: 0.1s;
transform-origin: top left;
animation-timing-function: linear;
animation-fill-mode: forwards;
opacity: 0.5;
}
body > p > span.slash {
transform: translate(30px, 270px) rotate(-45deg) translate(-15px, -15px);
animation-name: slash;
}
body > p > span.backslash {
transform: translate(30px, 30px) rotate(45deg) translate(-15px, -15px);
animation-name: backslash;
}
body > p > span.vert0 {
transform: translate(50px, 50px) rotate(90deg) translate(-15px, -15px);
animation-name: horivert;
}
body > p > span.vert1 {
transform: translate(150px, 50px) rotate(90deg) translate(-15px, -15px);
animation-name: horivert;
}
body > p > span.vert2 {
transform: translate(250px, 50px) rotate(90deg) translate(-15px, -15px);
animation-name: horivert;
}
body > p > span.hori0 {
transform: translate(50px, 50px) rotate(0deg) translate(-15px, -15px);
animation-name: horivert;
}
body > p > span.hori1 {
transform: translate(50px, 150px) rotate(0deg) translate(-15px, -15px);
animation-name: horivert;
}
body > p > span.hori2 {
transform: translate(50px, 250px) rotate(0deg) translate(-15px, -15px);
animation-name: horivert;
}
@keyframes backslash {
from { width: 0px; }
to { width: 370px; }
}
@keyframes slash {
from { width: 0px; }
to { width: 370px; }
}
@keyframes horivert {
from { width: 0px; }
to { width: 240px; }
}
.button {
box-sizing: border-box;
width: 300px;
background-color: #4CAF50; /* Green */
border: 1px solid black;
border-top: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 20pt;
}
</style>
</head>
<body>
<!-- <?=sizeof(array_keys($map))?>-->
<?php
$nbsp = html_entity_decode(" ");
$circle = html_entity_decode("○");
$cross = html_entity_decode("×");
foreach($map as $key => $step) {
$checked = $key == $step0key ? " checked" : "";
?>
<p><input type=radio name=s id=S<?=dechex($shortids[$key])?><?=$checked?>><?php
$won = array_key_exists($key, $wonmap) ? $wonmap[$key] : "";;
$wonlevel = substr($won, 1, 1);
switch (substr($won, 0, 1)) {
case "\\":
echo "<span class=backslash></span>\n";
break;
case "/":
echo "<span class=slash></span>\n";
break;
case "-":
echo "<span class=hori$wonlevel></span>\n";
break;
case "|":
echo "<span class=vert$wonlevel></span>\n";
break;
default:
}
for($y = 0; $y < 3; $y++) {
for($x = 0; $x < 3; $x++) {
$player = $step[$x][$y]['player'] == 1 ? $circle : ($step[$x][$y]['player'] == 2 ? $cross : $nbsp);
?><label for=S<?=dechex($shortids[$step[$x][$y]['stepkey']])?>><?=$player?></label><?php } ?><br/><?php } ?></p>
<?php
}
?>
<label for=S0 class=button>RESTART GAME</label>
</body>
</html>