Use WebGL to write a program that plays tic-tac-toe. The program should begin by drawing the game board (two vertical lines and two horizontal lines). When a player left-clicks on an open space, the program should draw an “X” in that square. When a player right-clicks on an open space, the program should draw an “O” in that square. The Xs must be different colors from the Os. Both of those colors must be different from the lines making the game board. In addition, each line or circle must have a width greater than one pixel.
Your program must not use any WebGL primitives other than points.
You must write and use your own method that draws a circle given a
center point and a radius. You must also write and use your own
method that draws a line given two endpoints. The circles should be
drawn using the Midpoint Circle algorithm. The lines should be
drawn using Bresenham’s Line algorithm.
Main HTML code for tic-tac-toe:
<html>
<head>
<script id="vBoardShader" type="x-shader/x-vertex">
attribute vec4 aValues;
varying vec2 vTextureCoord;
uniform vec2 uTextureCoord[16];
void main() {
int textureIndex = int(aValues.w);
vTextureCoord = uTextureCoord[textureIndex];
gl_Position = vec4(aValues.x, aValues.y, aValues.z, 1.);
}
</script>
<script id="fBoardShader" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uTexture;
void main() {
gl_FragColor = texture2D(uTexture, vTextureCoord);
//gl_FragColor = vec4(1., 0., 0., 1.);
}
</script>
<link type="text/css" rel="stylesheet" href="resources/ticTacToe.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
</head>
<body>
<canvas id="canvas" class="canvas" width="400" height="400"></canvas>
<div id="controls" class="control-panel">
<h1>Tic Tac Toe</h1>
<label>Choose a Setting:</label>
<form id="gameType">
<input id="PvP" type="radio" name="gameType" value="PvP"><label for="PvP">Player vs Player</label><br>
<input id="PvE" type="radio" name="gameType" value="PvE"><label for="PvE">Player vs Computer</label><br>
<input id="EvE" type="radio" name="gameType" value="EvE"><label for="EvE">Computer vs Computer</label><br>
</form>
<button id="start">Start</button>
<button id="reset">Reset</button>
</div>
<script type="text/javascript">
"use strict";
/* CONSTANTS */
// Web GL Only
var kTEXTURE_O = 0;
var kTEXTURE_X = 4;
var kTEXTURE_WHITE = 8;
var kTEXTURE_BLACK = 12;
// Constants for the Game
var kPOSITION_Y_TOP = 8;
var kPOSITION_Y_MID = 4;
var kPOSITION_Y_BOT = 0;
var kPOSITION_X_LEFT = 16;
var kPOSITION_X_MID = 28;
var kPOSITION_X_RIGHT = 40;
var kPOISTION_INVALID = -999;
var kSYMBOL_X = 36;
var kSYMBOL_O = 0;
var glContext, glCanvas, glProgram, glVertexBuffer, glIndexArray,
glIndexBuffer, glTexture, glValueArrLocation;
var bTextureReady = false;
var glGameVertexCoords = [];
var glTextureCoords = [];
/* Dynamically generates the cross-stitch grid for the game */
function generateGrid() {
var height = 1;
var width = .4;
var z = 0;
var texture = kTEXTURE_BLACK;
for (var i = 0; i < 16; i++) {
height *= -1;
if (i % 2 === 0) {
if (i != 0) {
if (Math.abs(width) === .4)
width = .3;
else
width = .4;
}
}
if (width > 0 && (i < 4 || (i >= 8 && i < 12))) {
width *= -1;
}
if (i >= 8) {
glGameVertexCoords.push(width);
glGameVertexCoords.push(height);
} else {
glGameVertexCoords.push(height);
glGameVertexCoords.push(width);
}
glGameVertexCoords.push(0);
glGameVertexCoords.push(texture + (i % 4));
}
}
/* Dynamically generates the panels for X and O */
function generatePanels(texture) {
var size = .6;
var baseXOffset = 0;
var baseYOffset = 0;
var xOffset = 0;
var yOffset = 0;
for (var i = 0; i < 36; i++) {
if (i % 4 === 0 && i != 0) {
baseYOffset += .7;
}
if (i % 12 === 0 && i != 0) {
baseXOffset += .7;
baseYOffset = 0;
}
yOffset = baseYOffset;
xOffset = baseXOffset;
if (i % 4 === 1) {
yOffset += size;
}
if (i % 4 === 2) {
xOffset += size;
}
if (i % 4 === 3) {
yOffset += size;
xOffset += size;
}
glGameVertexCoords.push((-1 + xOffset).toFixed(2));
glGameVertexCoords.push((-1 + yOffset).toFixed(2));
glGameVertexCoords.push(0);
glGameVertexCoords.push(texture + (i % 4));
}
}
glTextureCoords = [
// O
0.00, 0.25,
0.00, 0.00,
0.25, 0.25,
0.25, 0.00,
// X
0.25, 0.25,
0.25, 0.00,
0.50, 0.25,
0.50, 0.00,
// White
0.50, 0.25,
0.50, 0.00,
0.75, 0.25,
0.75, 0.00,
// Black
0.75, 0.25,
0.75, 0.00,
1.00, 0.25,
1.00, 0.00
];
/* Initalize the webgl program by compiling the shaders */
function initWebGL() {
glCanvas = document.getElementById("canvas");
// Get WebGl context
glContext = canvas.getContext("webgl");
if (!glContext) {
alert("Your browser does not support WebGl");
}
//Init Vertex Shader
var vSrc = document.getElementById("vBoardShader").text;
var vShader = glContext.createShader(glContext.VERTEX_SHADER);
glContext.shaderSource(vShader, vSrc);
glContext.compileShader(vShader);
//Init Fragment Shader
var fSrc = document.getElementById("fBoardShader").text;
var fShader = glContext.createShader(glContext.FRAGMENT_SHADER);
glContext.shaderSource(fShader, fSrc);
glContext.compileShader(fShader);
// link shaders to create our program
glProgram = glContext.createProgram();
glContext.attachShader(glProgram, vShader);
glContext.attachShader(glProgram, fShader);
glContext.linkProgram(glProgram);
glContext.useProgram(glProgram);
}
/* The texture needs to be loaded into the WebGL layer AFTER the image is
* "loaded" from the "server" */
function initTexture() {
glTexture = glContext.createTexture();
glTexture.image = new Image();
glTexture.image.onload = function () {
glContext.bindTexture(glContext.TEXTURE_2D, glTexture);
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA,
glContext.RGBA, glContext.UNSIGNED_BYTE,
glTexture.image);
glContext.generateMipmap(glContext.TEXTURE_2D);
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, glContext.LINEAR);
var uniformTextureLocation = glContext.getUniformLocation(glProgram, "uTexture");
glContext.uniform1i(uniformTextureLocation, 0);
bTextureReady = true;
};
glTexture.image.src = "resources/ticTacToeMap.png";
}
/* The first initalization of the arrays used by WebGL. The vertices and
* texture coordinate are loaded in here as well as the initial index
* array that draws the gird. */
function initArrays() {
generateGrid();
generatePanels(kTEXTURE_O);
generatePanels(kTEXTURE_X);
glIndexArray = [];
glDrawGrid();
// Enable the attribute array used to draw vertices
glValueArrLocation = glContext.getAttribLocation(glProgram, "aValues");
glContext.enableVertexAttribArray(glValueArrLocation);
//Vertex Buffer
glVertexBuffer = glContext.createBuffer();
glContext.bindBuffer(glContext.ARRAY_BUFFER, glVertexBuffer);
glContext.bufferData(glContext.ARRAY_BUFFER, new Float32Array(glGameVertexCoords), glContext.STATIC_DRAW);
glIndexBuffer = glContext.createBuffer();
glContext.bindBuffer(glContext.ELEMENT_ARRAY_BUFFER, glIndexBuffer);
glContext.bufferData(glContext.ELEMENT_ARRAY_BUFFER, new Uint16Array(glIndexArray), glContext.STATIC_DRAW);
glContext.vertexAttribPointer(glValueArrLocation, 4, glContext.FLOAT, false, 0, 0);
var uniformLoc = glContext.getUniformLocation(glProgram, "uTextureCoord");
// tell webgl how buffer is laid out (pairs of x,y coords)
glContext.uniform2fv(uniformLoc, new Float32Array(glTextureCoords));
}
/* The initalizations functions need to fire in a specific order. The
* WebGL layer might be delayed by the texture coming from the server. */
initWebGL();
initTexture();
var textureCheck = setTimeout(isTextureReady, 50);
function isTextureReady() {
if (bTextureReady) {
initArrays();
//Draw Grid
glUpdate();
window.clearInterval(textureCheck);
}
}
function glDrawGrid(){
for (var i = 0; i <= 12; i += 4) {
// Triangle 1
glIndexArray.push(i);
glIndexArray.push(i + 1);
glIndexArray.push(i + 2);
// Triangle 2
glIndexArray.push(i + 1);
glIndexArray.push(i + 2);
glIndexArray.push(i + 3);
}
}
// Master update function used to draw elements to the canvas
function glUpdate() {
//Clear the canvas
glContext.clear(glContext.COLOR_BUFFER_BIT);
//Update Index Buffer
glContext.bindBuffer(glContext.ELEMENT_ARRAY_BUFFER, glIndexBuffer);
glContext.bufferData(glContext.ELEMENT_ARRAY_BUFFER, new Uint16Array(glIndexArray), glContext.STATIC_DRAW);
// Draw
glContext.drawElements(glContext.TRIANGLES, glIndexArray.length, glContext.UNSIGNED_SHORT, 0);
}
// The WebGL function used to add an X or an O to the grid
function draw(symbol, x, y) {
var startVertex = x + y + symbol;
// Triangle 1
glIndexArray.push(startVertex);
glIndexArray.push(startVertex + 1);
glIndexArray.push(startVertex + 2);
// Triangle 2
glIndexArray.push(startVertex + 1);
glIndexArray.push(startVertex + 2);
glIndexArray.push(startVertex + 3);
glUpdate();
}
function clear(){
glIndexArray = [];
glDrawGrid();
glUpdate();
}
/*============================================================================*/
/* UI Management */
$('#start').click(function (e) {
if($('input[name="gameType"]:checked').length <= 0) {
alert("Please select a game type!");
return;
}
// This logic was based on:
// http://jsfiddle.net/codingsolver/MsYqx/
var gameType = $('input[name="gameType"]:checked', '#gameType').val();
startGame(gameType);
});
//Reset the game on reset click
$('#reset').click(reset);
// This logic was based on:
// http://stackoverflow.com/questions/3234977/using-jquery-how-to-get-click-coordinates-on-the-target-element
$('#canvas').click(function (e) { //Offset mouse Position
var posX = e.pageX - $(this).offset().left;
var posY = e.pageY - $(this).offset().top;
var x;
var y;
if(posY < 116)
y = kPOSITION_Y_TOP;
else if(posY > 141 && posY < 257)
y = kPOSITION_Y_MID;
else if(posY > 282)
y = kPOSITION_Y_BOT;
else
y = kPOSITION_INVALID;
if(posX < 116)
x = kPOSITION_X_LEFT;
else if(posX > 141 && posX < 257)
x = kPOSITION_X_MID;
else if(posX > 282)
x = kPOSITION_X_RIGHT;
else
x = kPOISTION_INVALID;
if(bUserTurn){
move(x, y);
}
});
/*============================================================================*/
/* Game Logic */
/* Constants */
var kGAME_TYPE_PVP = 0;
var kGAME_TYPE_PVE = 1;
var kGAME_TYPE_EVE = 2;
var gameType;
var bUserTurn = false;
var bCompTurn = false;
var bGameRunning = false;
var gameMode;
var turnSymbol;
var board = [['','',''],
['','',''],
['','','']];
function startGame(mode) {
turnSymbol = kSYMBOL_X;
bGameRunning = true;
gameMode = mode;
if (gameMode === 'PvP' || gameMode === 'PvE') {
bUserTurn = true;
} else {
bCompTurn = true;
computerMove();
}
}
function computerMove() {
setTimeout(function () {
var randX = Math.floor(Math.random() * 3);
var randY = Math.floor(Math.random() * 3);
while (board[randX][randY] !== '') {
randX = Math.floor(Math.random() * 3);
randY = Math.floor(Math.random() * 3);
}
var xConsts = [kPOSITION_X_LEFT, kPOSITION_X_MID, kPOSITION_X_RIGHT];
var yConsts = [kPOSITION_Y_TOP, kPOSITION_Y_MID, kPOSITION_Y_BOT];
move(xConsts[randX], yConsts[randY]);
}, 1000);
}
function move(x,y) {
if (bGameRunning) {
if (x === kPOISTION_INVALID || y === kPOISTION_INVALID) {
alert("Invalid Selection! Please try again");
return;
}
var boardX;
switch (x) {
case kPOSITION_X_LEFT:
boardX = 0;
break;
case kPOSITION_X_MID:
boardX = 1;
break;
case kPOSITION_X_RIGHT:
boardX = 2;
break;
}
var boardY;
switch (y) {
case kPOSITION_Y_TOP:
boardY = 0;
break;
case kPOSITION_Y_MID:
boardY = 1;
break;
case kPOSITION_Y_BOT:
boardY = 2;
break;
}
if (board[boardX][boardY] === '') {
board[boardX][boardY] = turnSymbol;
draw(turnSymbol, x, y);
} else {
alert("Selection Already Taken. Please try again.");
return;
}
if (!evaluateGame()) {
swapSymbol();
if (gameMode === 'PvE') {
bCompTurn = bUserTurn;
bUserTurn = !bUserTurn;
}
if (bCompTurn) {
computerMove();
}
}
}
}
function reset() {
bGameRunning = false;
board = [['', '', ''],
['', '', ''],
['', '', '']];
clear();
}
function swapSymbol() {
if (turnSymbol === kSYMBOL_O) {
turnSymbol = kSYMBOL_X;
} else
turnSymbol = kSYMBOL_O;
}
// I'm aware of the nested for loop in this function but this grid is 3x3
// so I didn't feel the need to optimize. Just like if the grid isn't full
// enough for a win this check will still occur. TODO:Optimize this check and when it occurs
function evaluateGame() {
//Diagonal Check 1
if (board[0][0] !== '' && board[1][1] !== '' && board[2][2] !== '' &&
board[0][0] === board[1][1] && board[1][1] === board[2][2]) {
console.log('Diagonal :' + 0 + '' + 0 + ' Wins!');
win(board[0][0]);
return true;
}
//Diagonal Check 2
if (board[0][2] !== '' && board[1][1] !== '' && board[2][0] !== '' &&
board[0][2] === board[1][1] && board[1][1] === board[2][0]) {
console.log('Diagonal :' + 0 + '' + 2 + ' Wins!');
win(board[0][2]);
return true;
}
for (var i = 0; i < board.length; i++) {
//Column Check
if (board[i][0] != '' && board[i][0] === board[i][1] &&
board[i][1] === board[i][2]) {
console.log('Column :' + i + ' Wins!');
win(board[i][0]);
return true;
}
//Row
if (board[0][i] != '' && board[0][i] === board[1][i] &&
board[1][i] === board[2][i]) {
console.log('Row :' + i + ' Wins!');
win(board[0][i]);
return true;
}
}
for (var i = 0; i < board.length; i++) {
//Check for empty slots
for (var j = 0; j < board[i].length; j++) {
if (board[i][j] === '')return false;
}
}
stalemate();
return true;
}
function win(symbol) {
console.log(symbol);
if (kSYMBOL_O === symbol) {
alert('O wins!');
} else if (kSYMBOL_X === symbol) {
alert('X wins!');
} else
alert('Oops! This shouldn\'t happen! Symbol: ' + symbol);
bGameRunning = false;
bUserTurn = false;
}
function stalemate() {
alert('Stalemate!');
}
</script>
</body>
</html>
CSS code:
.canvas{
float: left;
}
.control-panel{
display: inline-block;
height: 100%;
width: 50%;
}
Map file:
Use WebGL to write a program that plays tic-tac-toe. The program should begin by drawing the...
(Tic-Tac-Toe) Create a class Tic-Tac-Toe that will enable you to write a program to play Tic-Tac-Toe. The class contains a private 3-by-3 two-dimensional array. Use an enumeration to represent the value in each cell of the array. The enumeration’s constants should be named X, O and EMPTY (for a position that does not contain an X or an O). The constructor should initialize the board elements to EMPTY. Allow two human players. Wherever the first player moves, place an X...
18. Tic-Tac-Toe Game rite a program that allows two players to play a game of tic-tac-toe. Use dimensional char array with three rows and three columns as the game board. Each element of the array should be initialized with an asterisk (*). The program should run a loop that does the following: Write . Displays the contents of the board array. . Allows player 1 to select a location on the board for an X. The program should ask the...
Write a program to Simulate a game of tic tac toe. A game of tic tac toe has two players. A Player class is required to store /represent information about each player. The UML diagram is given below.Player-name: string-symbol :charPlayer (name:string,symbol:char)getName():stringgetSymbol():chargetInfo():string The tic tac toe board will be represented by a two dimensional array of size 3 by 3 characters. At the start of the game each cell is empty (must be set to the underscore character ‘_’). Program flow:1) ...
JAVAFX PROGRAM Write a program that will allow two users to play a game of tic-tac-toe. The game area should consist of nine buttons for the play area, a reset button, and a label that will display the current player's turn. When the program starts, the game area buttons should have no values in them (i.e. they should be blank) When player one clicks on a game area button, the button should get the value X. When player two clicks...
Tic-Tac-Toe Game Write a program that allows two players to play a game of tic-tac-toe. Use a two-dimensional char array with three rows and three columns as the game board. Each element of the array should be initialized with an asterisk (*). The program should run a loop that does the following: Displays the contents of the board array. Allows player 1 to select a location on the board for an X. The program should ask the user to enter...
Please make this into one class. JAVA Please: Tic Tac Toe class - Write a fifth game program that can play Tic Tac Toe. This game displays the lines of the Tic Tac Toe game and prompts the player to choose a move. The move is recorded on the screen and the computer picks his move from those that are left. The player then picks his next move. The program should allow only legal moves. The program should indicate when...
JAVA TIC TAC TOE - please help me correct my code Write a program that will allow two players to play a game of TIC TAC TOE. When the program starts, it will display a tic tac toe board as below | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 The program will assign X to Player 1, and O to Player The program will ask Player 1, to...
Write a c program that will allow two users to play a tic-tac-toe game. You should write the program such that two people can play the game without any special instructions. (assue they know how to play the game). Prompt first player(X) to enter their first move. .Then draw the gameboard showing the move. .Prompt the second player(O) to enter their first move. . Then draw the gameboard showing both moves. And so on...through 9 moves. You will need to:...
1. Use Turtle Graphics to create a tic tac toe game in Python. Write a Python program that allows for one player vs computer to play tic tac toe game, without using turtle.turtle
(Tic-Tac-Toe) Create class TicTacToe that will enable you to write a complete app to play the game of Tic-Tac-Toe. The class contains a private 3-by-3 rectangular array of integers. The constructor should initialize the empty board to all 0s. Allow two human players. Wherever the first player moves, place a 1 in the specified square, and place a 2 wherever the second player moves. Each move must be to an empty square. After each move, determine whether the game has...