JSFiddle - React, Tailwind, and code Playground

by outis

HTML

<div id="h8">
  <div id="board">             
	<div id="sq0" onclick="move(0)"><div id="xo0"><span class="ex">&emsp;</span></div></div>
	<div id="sq1" onclick="move(1)"><div id="xo1"><span class="ex">&emsp;</span></div></div>
	<div id="sq2" onclick="move(2)"><div id="xo2"><span class="ex">&emsp;</span></div></div><br/>

	<div id="sq3" onclick="move(3)"><div id="xo3"><span class="ex">&emsp;</span></div></div>
	<div id="sq4" onclick="move(4)"><div id="xo4"><span class="ex">&emsp;</span></div></div>
	<div id="sq5" onclick="move(5)"><div id="xo5"><span class="ex">&emsp;</span></div></div><br/>

	<div id="sq6" onclick="move(6)"><div id="xo6"><span class="ex">&emsp;</span></div></div>
	<div id="sq7" onclick="move(7)"><div id="xo7"><span class="ex">&emsp;</span></div></div>
	<div id="sq8" onclick="move(8)"><div id="xo8"><span class="ex">&emsp;</span></div></div><br/>
</div></div>


<div id="msgX">X Wins</div>
<div id="msgO">O Wins</div>
<div id="h"></div>

<button id="ng" onclick="newgame();">New Game</button>

CSS

html,body{padding:0 0 0 5px;}
		#board > div {
			cursor: pointer;
		}
		#board#h8{width:255px;margin:0;padding:0;border:0;}
		#sq1,#sq2,#sq3,#sq4,#sq5,#sq6,#sq7,#sq8,#sq9{width:80px;height:80px;:inline-block;border:2px solid black;display:inline-block;
			background: linear-gradient(to bottom, #444 0%, #111 100%);}
		#xo1,#xo2,#xo3,#xo4,#xo5,#xo6,#xo7,#xo8,#xo9{padding:0 0 0 16px;color:#fff;font:700 60px Arial,sans-serif;display:inline-block;}
		.oh{font-size:66px;color:#ff0;}
		.ex{font-size:66px;color:#f0f;}
		button{color:#fff;width:251px;background: linear-gradient(to bottom, rgba(0,0,255,1) 0%, rgba(0,0,64,1) 100%);}
		#prefetch{display:none;}
		#h8{opacity:1;}
		#msg8,#msg64{display:none;width:250px;text-align:center;font:700 40px Arial,sans-derif;color:#f00;}
		#ng{font:700 33px Arial,sans-serif;}

JavaScript

(function () {
	const xo = [null,null,null,null,null,null,null,null,null,null],
		  // bitmasks for lines of squares
		  lines = [
			  0b000000000000111111,
			  0b000000111111000000,
			  0b111111000000000000,
			  
			  0b000011000011000011,
			  0b001100001100001100,
			  0b110000110000110000,

			  0b110000001100000011,
			  0b000011001100110000,
		  ],
		  // which line each square participates in; indexes into lines
		  participation = [
			  [0, 3, 6],
			  [0, 4],
			  [0, 5, 7],

			  [1, 3],
			  [1, 4, 6, 7],
			  [1, 5],

			  [2, 3, 7],
			  [2, 4],
			  [2, 5, 6],
		  ],
		  wins = {
			  0b000000000000010101: 0,
			  0b000000000000101010: 1,
			  0b000000010101000000: 0,
			  0b000000101010000000: 1,
			  0b010101000000000000: 0,
			  0b101010000000000000: 1,
			  
			  0b000001000001000001: 0,
			  0b000010000010000010: 1,
			  0b000100000100000100: 0,
			  0b001000001000001000: 1,
			  0b010000010000010000: 0,
			  0b100000100000100000: 1,

			  0b010000000100000001: 0,
			  0b100000001000000010: 1,
			  0b000001000100010000: 0,
			  0b000010001000100000: 1,
		  },
		  h = {
			  0: document.getElementById('h8'),
			  1: document.getElementById('h8'),
			  2: document.getElementById('h'),
		  },
		  msg = {
			  0: document.getElementById('msgX'),
			  1: document.getElementById('msgO'),
			  2: document.getElementById('h'),
		  },
		  img = ['<span class="ex">X</span>','<span class="oh">&#927;</span>','<span class="ex">&emsp;</span>'];

	for (let i = 0; i < xo.length; ++i) {
		xo[i] = document.getElementById('xo' + i);
	}
	
	var player = 0,
		board = 0x0;

	function win(id) {
		for (let line of participation[id]) {
			line = lines[line] & board;
			if (line in wins) {
				return wins[line];
			}
		}
		return 2;
	}

	function square(id) {
		return 0x3 & (board >> (id * 2));
	}

	function setSquare(id, val) {
		board |= ((val & 0x3) << (id * 2));
	}

	function move(id) {
		let prev = square(id),
			empty = ! prev;
		setSquare(id, prev || (player...