An Interest In:
Web News this Week
- March 21, 2024
- March 20, 2024
- March 19, 2024
- March 18, 2024
- March 17, 2024
- March 16, 2024
- March 15, 2024
October 8, 2021 01:45 am GMT
Original Link: https://dev.to/abhidevelops/unbeatable-emoji-tic-tac-toe-10jh
Unbeatable Emoji Tic Tac Toe
Hi Everyone!
In this post, I will show you how to make an unbeatable emoji tic-tac-toe that makes fun of you if you make a move or lose. It is made with HTML, CSS, and Javascript. You cannot win this game. The most you can get is a draw. Follow me if you want more projects.
Let's start with the HTML Design:
<!DOCTYPE html><html> <head> <link rel="stylesheet" href="style.css> <title>Unbeatable Tic Tac Toe | Abhinav Gupta</title> </head><body><section id="start-select"> <div> <div> <h3>Go First or Second?</h3> <button id="1st" class="active" onclick="pickTurn(true);" style='font-size: 14px;'>1st</button><button id="2nd" onclick="pickTurn(false);" style='font-size: 14px;'>2nd</button> <h3>Choose Your Character</h3> <span id="charSymbols"></span> <button id ="start-btn" onclick="startGame();" style='font-size: 18px;'>Start Game</button> </div> </div></section><header id="header" style="opacity:0.6;"> <div id="emoji-outer-div"> <div id="emoji"> <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/win02.png" id="emoji-img"> </div> <div id="emoji-text"> <span id="aiTalk">"Hi, I'm Unbeatable-AI<br>Wanna Play Against Me?"</span> </div> </div></header> <nav id="menu-nav"> <div> <div> <h3>Next Round Go First or Second?</h3> <button id="1st-next" class="active" onclick="pickTurn(true);">1st</button><button id="2nd-next" onclick="pickTurn(false);">2nd</button> <h3>Change Your Character</h3> <span id="menu-chars"></span> <button id ="menu-close" onclick="openMenu(false);" style="">Close</button> </div> </div></nav><section id='main-section' style="opacity:0.6;"> <section id="side-section"> <a id="menu-open" href="javascript:void(0);" onclick="openMenu(true);"><div>☰</div></a> <div id="score"> <div><span>Score</span></div> <div><table> <tr> <th>You</th> <th style="width: 12px;"></th> <th>Ai</th> </tr> <tr> <td>0</td> <td> </td> <td id="score-ai">0</td> </tr> </table></div> <div style="height: 10px; width:0;"></div> <div><table> <tr> <th>Tie</th> </tr> <tr> <td id="score-tie">0</td> </tr> </table></div></div> </section> <div id="outer-grid"><section id="grid"> <div id="pos0"><a href="javascript:void(0);" onclick='playerMove(0);' class="pos"></a></div> <div id="pos1"><a href="javascript:void(0);" onclick='playerMove(1);' class="pos"></a></div> <div id="pos2"><a href="javascript:void(0);" onclick='playerMove(2);' class="pos"></a></div> <div id="pos3"><a href="javascript:void(0);" onclick='playerMove(3);' class="pos"></a></div> <div id="pos4"><a href="javascript:void(0);" onclick='playerMove(4);' class="pos"></a></div> <div id="pos5"><a href="javascript:void(0);" onclick='playerMove(5);' class="pos"></a></div> <div id="pos6"><a href="javascript:void(0);" onclick='playerMove(6);' class="pos"></a></div> <div id="pos7"><a href="javascript:void(0);" onclick='playerMove(7);' class="pos"></a></div> <div id="pos8"><a href="javascript:void(0);" onclick='playerMove(8);' class="pos"></a></div></section> </div></section><script href="script.js"></script> </body></html>
Next, let's make the CSS for the nice neat look:
* { box-sizing: border-box; font-family: 'Cabin', sans-serif;}a { text-decoration: none; color: inherit;}button:focus {outline:0;}body { margin: 20px auto; padding: 5px; max-width: 510px; background-color: #4ECCB0;}#start-select { position: absolute; width: 100vw; height: 100vh; z-index: 100; left: 50%; top: 40%; transform: translate(-50%,-50%);}#start-select div { position: fixed; display: flex; left: 50%; top: 50%; transform: translate(-50%,-50%); width: 350px; height: 300px; border-radius: 35px; background-color: #5A8BCE; box-shadow: 3px 3px 6px #0B3A97;}#start-select div div { display: flex; justify-content: center; flex-wrap: wrap; left: 50%; top: 50%; transform: translate(-50%,-50%);}#start-select div div h3 { margin: auto; text-align: center; width: 100%;}#start-select div div span { display: flex; flex-wrap: wrap; justify-content: center;}#start-select div div button { background-color: #4ECCB0; border-radius: 8px; margin: 3px; padding: 15px; height: 50px; min-width: 55px; border: none; -webkit-transition: background-color 500ms; /* Safari */ transition: background-color 500ms;}#start-select div div button:hover { background-color: #77E0C9; box-shadow: 0.5px 0.5px 5px black; cursor: pointer; cursor: hand; -webkit-transition: background-color 300ms; /* Safari */ transition: background-color 300ms;}#start-select div div button.active { border: 2px solid; background-color: #2EB798; padding: 13px; -webkit-transition: background-color 500ms; /* Safari */ transition: background-color 500ms;}#start-select div div button.charBtn { min-width: 40px; height: 40px; width: 40px; text-align: center; padding: 6px;}header { display: flex; height: 110px; margin: 0 15px; opacity: 1; -webkit-transition: opacity 750ms; /* Safari */ transition: opacity 750ms;}#emoji-outer-div { flex: 1; display: flex; align-items: center;}#emoji { width: 100px; height: 100px;}#emoji img { height: 100%;}#emoji-text { flex: 1; text-align: center; margin: 0 30px; font-size: 20px;}#aiTalk { font-family: 'Poiret One', Segoe, sans-serif; font-weight: bold;}nav { display: none; position: absolute; width: 100vw; height: 100vh; z-index: 99; left: 50%; top: 50%; transform: translate(-50%,-50%);}nav div { position: fixed; display: flex; left: 50%; top: 50%; transform: translate(-50%,-50%); width: 310px; height: 350px; border-radius: 35px; background-color: #5A8BCE; box-shadow: 3px 3px 6px #0B3A97;}nav div div { display: flex; justify-content: center; flex-wrap: wrap; left: 50%; top: 50%; transform: translate(-50%,-50%);}nav div div h3 { margin: auto; text-align: center; width: 100%;}nav div div span { width: 270px; display: flex; flex-wrap: wrap; justify-content: center;}nav div div button { background-color: #4ECCB0; border-radius: 8px; margin: 3px; padding: 15px; height: 50px; min-width: 55px; border: none; -webkit-transition: background-color 750ms; /* Safari */ transition: background-color 750ms;}nav div div button:hover { background-color: #77E0C9; box-shadow: 0.5px 0.5px 5px black; cursor: pointer; cursor: hand; -webkit-transition: background-color 300ms; /* Safari */ transition: background-color 300ms;}nav div div button.active { border: 2px solid; background-color: #2EB798; padding: 13px; -webkit-transition: background-color 500ms; /* Safari */ transition: background-color 500ms;}nav div div button.charBtn { min-width: 40px; height: 40px; width: 40px; text-align: center; padding: 6px;}#main-section { display: flex; flex-wrap: wrap; margin: auto; opacity: 1; -webkit-transition: opacity 500ms; /* Safari */ transition: opacity 500ms;}#side-section { margin: 15px;}#menu-open div { margin: auto; text-align: center; width: 60px; border-radius: 10px; font-size: 35px; border: solid #009271; margin: 25px; padding: 2.5px; background-color: #1BA485;}#menu-open div:hover { background-color: #28C09E; border: solid #009271;}#score { margin: auto;}#score table, #score div { font-size: 20px; text-align: center; margin: auto; display: flex;}tr, th, td { padding: 1px;}#score div span { font-size: 25px; margin: 10px auto;}@media screen and (max-width: 530px) { body { margin: 10px auto; padding: 5px; } header { margin: auto; max-width: 400px; } #emoji-text { margin: 0 10px; font-size: 20px; } #emoji { height: 65px; width: 65px; } #start-select div { width: 300px; height: 380px; padding: 13px; } #score-2 { position: relative; right: 15px; } #menu-open div { margin: 0 5px; } #score { margin: auto; display: flex; flex: 1; } #side-section { margin: auto; width: 360px; display: flex; }}#outer-grid { height: 300px; width: 300px; margin: 8px auto;}@media screen and (min-width: 380px) { #outer-grid { width: 360px; height: 360px; margin: 15px auto; }}#grid { height: 100%; width: 100%; display: flex; flex-wrap: wrap;}#grid div { width: 33.3%; height: 33.3%; padding: 2.5px; display: flex;}#grid div div, #grid div a { background-color: #134DBF; text-shadow: 1px 1px grey; font-size: 45px; width: 100%; height: 100%; text-align: center; border-radius: 15px; display: flex; box-shadow: 2px 2px 4px #008B81;}#grid div div.taken { background-color: #0B3A96; box-shadow: 4px 4px 5px #008B81;}#grid div div.win { background-color: #E26200; box-shadow: 4px 4px 5px #008B81;}#grid div div span { margin: auto;}.pos-span { opacity: 0; display: flex; width: 100%; height: 100%; -webkit-transition: opacity 250ms; /* Safari */ transition: opacity 250ms;}.pos-span span { margin: auto;}.pos-span:hover { opacity: 0.4; -webkit-transition: opacity 550ms; /* Safari */ transition: opacity 550ms;}#grid div div:hover { background-color: #0B3A96; box-shadow: 4px 4px 5px #008B81; -webkit-transition: background-color 300ms; /* Safari */ transition: background-color 300ms;}
Lastly, let's write the Javascript to actually make it "Unbeatable":
var aiTalksWin = [[["win4"],"Sorry, humans made me to powerful!"], [["win01"],"Honestly, I thought you could win, but I guess I was wrong."], [["win02"],"<del>Win Tic-Tac-Toe?</del> <br>2. First, win against ME!"], [["win3"],"What Did You Expect? You Are Only a Human..."], [["win01"],"Unbeatable Is In My Name, I can't do it is in yours."], [["win3"],"The score counter is pointless."], [["win4"],"Let You Win? I'm Afraid I Can't Do That."], [["win02"],""]];var aiTalksMove = [[["move00"],"..."], [["move00"],"Hmmm..."], [["move05"],"Go AI !!"], [["move08"],"Sadness is Victory"],[["move08"], "Your Defeat Is a WIN for me..."], [["move03"],"Nice Try (not)"], [["move03"],"Knock Knock. Who's there? R O B O T"], [["move4"],"There are 255,168 Possible Board Combinations, Yet You Picked That One?"], [["win4"],"Infinity x Infinity Wins for me, not you!"], [["draw02"],"When Was The Last Time You Rebooted Your Device?"], [["draw04"],"I feel strange..."], [["move01"],"A Wise Computer Once Told Me That The Meaning Of Life Is 42"], [["draw01"],"Whoops, wrong move."], [["win02"],"The end is upon! "], [["move06"], "Can't Touch This!"], [["move07"], "Your Last Move Goes In The loosing Category"]];var aiTalksTie = [[["draw01"],"..."], [["draw02"],"..."], [["draw03"],"..."], [["draw04"],"..."]];// </> Ai Talkingfunction randomEmoji(chance, arr) { var randTest = Math.random() < chance; if (randTest) { var rand = Math.floor(Math.random()*arr.length); console.log(rand); document.getElementById("emoji-img") .src = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/"+arr[rand][0][0]+".png"; document.getElementById("aiTalk") .innerHTML = '"'+arr[rand][1]+'"'; }}var winCond = [[0,1,2],[3,4,5],[6,7,8], [0,3,6],[1,4,7],[2,5,8], [0,4,8],[2,4,6]];var gameMain = ["0", "0", "0", "0", "0", "0", "0", "0", "0"]; var chars = ["01","02","03","04","05","06","07","08","09","10","11","12","13"];function charsBtnGen() { for (var i = 0; i < chars.length; i++) { document.getElementById("charSymbols").innerHTML += '<button id="char'+i+'" class="charBtn" onclick="chrChoose('+i+');"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/icon'+chars[i]+'.png" style="width: 25px"></button>'; document.getElementById("menu-chars").innerHTML += '<button id="char-chng'+i+'" class="charBtn" onclick="chrChange('+i+');"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/icon'+chars[i]+'.png" style="width: 25px"></button>'; }} function openMenu(open) { if (open) { document.getElementById('menu-nav').style.display = 'flex'; document.getElementById('header').style.opacity = '0.6'; document.getElementById('main-section').style.opacity = '0.6'; } else { document.getElementById('menu-nav').style.display = 'none'; document.getElementById('header').style.opacity = ''; document.getElementById('main-section').style.opacity = ''; }}var aiChar = 'O';var plChar = 'X';var aiScore = 0;var tieScore = 0;var gameStarted = false;// --- \/ \/ \/ Before Game Start \/ \/ \/ ---// </> Player 1st or 2nd plFirst = true;function pickTurn(first) { if (first) { document.getElementById("1st").className = "active"; document.getElementById("2nd").className = ""; document.getElementById("1st-next").className = "active"; document.getElementById("2nd-next").className = ""; } if (!first) { document.getElementById("2nd").className = "active"; document.getElementById("1st").className = ""; document.getElementById("2nd-next").className = "active"; document.getElementById("1st-next").className = ""; } plFirst = first;}// </> Character Chooserfunction chrChoose(x) { for (var i = 0; i < chars.length; i++) { document.getElementById("char"+i).className = "charBtn"; } document.getElementById("char"+x).className += " active"; plChar = chars[x];}// </> Character Changefunction chrChange(x) { for (var i = 0; i < chars.length; i++) { document.getElementById("char-chng"+i).className = "charBtn"; } document.getElementById("char-chng"+x).className += " active"; if (aiChar === chars[x]) { var y = -1; while (y === x || y === -1) {y = Math.floor(Math.random()*chars.length);} for (var j = 0; j < 9; j++) { if (gameMain[j] === aiChar) { gameMain[j] = chars[y]; document.getElementById("div"+j) .innerHTML = "<span style='display: flex;'><img src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/icon"+chars[y]+".png' style='width: 50px; margin: auto;'></span>"; } } aiChar = chars[y]; } // "<span style='display: flex;'><img src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/icon"+chars[x]+".png' style='width: 50px; margin: auto;'></span>" for (var i = 0; i < 9; i++) { if (gameMain[i] === plChar) { gameMain[i] = chars[x]; document.getElementById("div"+i) .innerHTML = "<span style='display: flex;'><img src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/icon"+chars[x]+".png' style='width: 50px; margin: auto;'></span>"; } else if (gameMain[i] === "0") { document.getElementById("transpChars"+i) .innerHTML = "<span style='display: flex;'><img src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/icon"+chars[x]+".png' style='width: 50px; margin: auto;'></span>"; } } plChar = chars[x];}// </> Random Ai Charfunction randChar() { var rand = Math.floor(Math.random()*chars.length); aiChar = chars[rand]; if (aiChar === plChar) {return randChar();} return; }// </> Start Gamevar round = 0;function startGame() { gameStarted = true; plMoveDisable = false; document.getElementById('start-select').style.display = 'none'; document.getElementById('header').style.opacity = ''; document.getElementById('main-section').style.opacity = ''; if (round === 0) { document.getElementById("aiTalk").innerHTML = '"Have Fun"'; document.getElementById("emoji-img").src = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/win3.png"; } round++; !function () { var randPl = Math.floor(Math.random()*chars.length); if (plChar === "X") {plChar = chars[randPl];} }(); randChar(); var pos = document.getElementsByClassName("pos"); for (var i = 0; i < 9; i++) { pos[i].innerHTML = '<div><span class="pos-span"><span id="transpChars'+i+'"><span style="display: flex;"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/icon'+plChar+'.png" style="width: 50px; margin: auto;"></span></span></span></div>'; } if (!plFirst) { aiTurn(); }}// --- /\ /\ /\ Before Game Start /\ /\ /\ ---// --- \/ \/ \/ After Game Start \/ \/ \/ ---// </> Checks for Victoryfunction checkVictory(who) { var inx = [], i; for (i = 0; i < 9; i++) { if (gameMain[i] === who) { inx.push(i); } } for (var j = 0; j < 8; j++) { var win = winCond[j]; if (inx.indexOf(win[0]) !== -1 && inx.indexOf(win[1]) !== -1 && inx.indexOf(win[2]) !== -1) { randomEmoji(1, aiTalksWin); for (let k = 0; k < 3; k++) { setTimeout(function() { document.getElementById("div"+win[k]).className = "win"; },350*(k+1)); } gameStarted = false; aiScore++; document.getElementById("score-ai").innerHTML = aiScore; setTimeout(function() {restart("tie");},2000); return true; } } if (gameMain.indexOf("0") === -1) { gameStarted = false; randomEmoji(1, aiTalksTie); setTimeout(function() { for (let k = 0; k < 9; k++) { setTimeout(function() { document.getElementById("div"+[k]).innerHTML = ""; },125*(k+1)); } },500); setTimeout(function() {restart("tie");},2100); tieScore++; document.getElementById("score-tie").innerHTML = tieScore; return true; } else if (who === aiChar && gameMain.indexOf(plChar) !== -1) {randomEmoji(0.3, aiTalksMove);} return false; }// </> Restart Gamefunction restart(x) { for (var i = 0; i < 9; i++) { document.getElementById("pos"+i).innerHTML = '<a href="javascript:void('+i+');" onclick="playerMove('+i+');" class="pos"></a>'; } gameMain = ["0", "0", "0", "0", "0", "0", "0", "0", "0"]; startGame(); disableRestart = false;}// </> Write a Movefunction writeOnGame(pos, char) { gameMain[pos] = char; document.getElementById("pos"+pos) .innerHTML = "<div class='taken' id='div"+pos+"'><span style='display: flex;'><img src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/1134440/icon"+char+".png' style='width: 50px; margin: auto;'></span></div>";}// </> Ai Triger and Equal Value Ai Move Randomizerfunction aiTurn() { var posArr = ai(); var ran = Math.floor(Math.random() * posArr.length); writeOnGame(posArr[ran], aiChar); checkVictory(aiChar);}// </> Player Clickvar plMoveDisable = falsefunction playerMove(pos) { if (gameStarted && !plMoveDisable) { plMoveDisable = true; writeOnGame(pos, plChar); var win = checkVictory(plChar); if (win) {return;} setTimeout(function() { aiTurn(); plMoveDisable = false; },450); }}// --- /\ /\ /\ After Game Start /\ /\ /\ ---// --- \/ \/ \/ AI \/ \/ \/ ---// </> MinMax algofunction ai() { if (gameStarted) { function isOpen(gameState,pos) { return gameState[pos] === "0"; } function didWin(gameState, val) { var inx = [], i; for (i = 0; i < 9; i++) { if (gameState[i] === val) { inx.push(i); } } for (var i = 0; i < 8; i++) { if (inx.indexOf(winCond[i][0]) !== -1 && inx.indexOf(winCond[i][1]) !== -1 && inx.indexOf(winCond[i][2]) !== -1) { return true; } } return false; } function findScore(scores, x) { if (scores.indexOf(x) !== -1) {return x;} else if (scores.indexOf(0) !== -1) {return 0;} else if (scores.indexOf(x * -1) !== -1) {return x * -1;} else {return 0;} } var scoresMain = ['0','0','0','0','0','0','0','0','0']; function findBestMove() { // MAIN FUNCTION for (var i = 0; i < 9; i++) { if (isOpen(gameMain, i)) { var simGame = gameMain.slice(); simGame[i] = aiChar; if (didWin(simGame, aiChar)) { scoresMain[i] = 1; } else { scoresMain[i] = plSim(simGame); } } } var bigest = -99; for (var j = 0; j < 9; j++) { if (scoresMain[j] !== '0' && scoresMain[j] > bigest) { bigest = scoresMain[j]; } } var inx = [], i; for (i = 0; i < 9; i++) { if (scoresMain[i] === bigest) { inx.push(i); } } console.log(gameMain.slice(0,3), scoresMain.slice(0,3)); console.log(gameMain.slice(3,6), scoresMain.slice(3,6)); console.log(gameMain.slice(6,9), scoresMain.slice(6,9)); return inx; } function plSim(simGame) { // PL SIM var simGameTest = simGame.slice(); for (var i = 0; i < 9; i++) { if (isOpen(simGame, i)) { simGameTest = simGame.slice(); simGameTest[i] = plChar; if (didWin(simGameTest, plChar)) { return -1; } } } var plScores = ['0','0','0','0','0','0','0','0','0']; for (var j = 0; j < 9; j++) { if (isOpen(simGame, j)) { simGameTest = simGame.slice(); simGameTest[j] = plChar; plScores[j] = aiSim(simGameTest); } } return findScore(plScores, -1); } function aiSim(simGame) { // AI SIM var simGameTest = simGame.slice(); for (var i = 0; i < 9; i++) { if (isOpen(simGame, i)) { simGameTest = simGame.slice(); simGameTest[i] = aiChar; if (didWin(simGameTest, aiChar)) { return 1; } } } var aiScores = ['0','0','0','0','0','0','0','0','0']; for (var j = 0; j < 9; j++) { if (isOpen(simGame, j)) { simGameTest = simGame.slice(); simGameTest[j] = aiChar; aiScores[j] = plSim(simGameTest); } } return findScore(aiScores, 1); } // aiSim() return findBestMove(); }} // ai() endcharsBtnGen();
That's It! You have now successfully created an Unbeatable Emoji Tic-Tac-Toe.
Original Link: https://dev.to/abhidevelops/unbeatable-emoji-tic-tac-toe-10jh
Share this article:
Tweet
View Full Article
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To