Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tic Tac Toe #157

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 3 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
# 📊 Morning Challenge: Tic-Tac-Toe
## Project:Tic-Tac-Toe

### Goal: Create a two player Tic-Tac-Toe game. The users should be able to click to place their X or O and if they win the program should mention their win in the DOM. Please make the game as OOP as possible.
### Goal: Two player Tic-Tac-Toe game. Users click to place their X or O. If they win the program mentions their win in the DOM, and keeps score.

### How to submit your code for review:

- Fork and clone this repo
- Create a new branch called answer
- Checkout answer branch
- Push to your fork
- Issue a pull request
- Your pull request description should contain the following:
- (1 to 5 no 3) I completed the challenge
- (1 to 5 no 3) I feel good about my code
- Anything specific on which you want feedback!

Example:
```
I completed the challenge: 5
I feel good about my code: 4
I'm not sure if my constructors are setup cleanly...
```
<img width="1440" alt="Screenshot 2024-11-01 at 9 43 11 PM" src="https://github.com/user-attachments/assets/a573351d-ba1d-4b77-afec-f78a7e90a0fa">
52 changes: 52 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Permanent+Marker&family=Rock+Salt&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<title>Tic Tac Toe</title>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<div id="status"></div>

<div id="board">
<div class="square" id="0"></div>
<div class="square" id="1"></div>
<div class="square" id="2"></div>
<div class="square" id="3"></div>
<div class="square" id="4"></div>
<div class="square" id="5"></div>
<div class="square" id="6"></div>
<div class="square" id="7"></div>
<div class="square" id="8"></div>
</div>
<div id="restart">
<input type="button" value="Restart" id="restartButton"/>
</div>
<div class="scoreboard">
<h2>Scoreboard</h2>
<table class="score">
<tbody>
<tr>
<td id="playeronescore">0</td>
<td id="playertwoscore">0</td>
</tr>
</tbody>
<tfoot>
<tr>
<th> Player 1 </th>
<th> Player 2 </th>
</tr>
</tfoot>
</table>
</div>
<script src="main.js"></script>
</body>
</html>
107 changes: 107 additions & 0 deletions main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
class Game{
constructor(){
this.curPlayer='X' ///X starts the game
this.board=Array(9).fill(null) //Array to track the board of 9 empty squares
this.score={X:0, O:0} //Tracks scores for X and O
this.winner=null //no winner at start of game

//Select DOM elements
this.squares=document.querySelectorAll('.square') //selects each square(cell)
this.restart=document.querySelector('#restartButton') //selects restart button
this.playeronescore=document.querySelector('#playeronescore') //selects player one score
this.playertwoscore=document.querySelector('#playertwoscore') //selects player two score
this.status=document.querySelector('#status') //selcts status to display who won

}

init(){
this.squares.forEach(square => square.addEventListener('click',(e)=> this.handleCellClick(e)))
this.restart.addEventListener('click',()=>this.restartButton())
this.updateStatus()
}
handleCellClick(event){
const index=event.target.id //Gets the id element when square(cell) is clicked
const cell=event.target //Tracks clicked cell

if(this.board[index] === null && !this.winner){//checks if cells have been clicked and if there is no winner
this.board[index]=this.curPlayer //fills cell with curPlayers symbol
cell.textContent=this.curPlayer //fills square with curPlayers symbol
if(this.checkWin(this.board)){ //checks to see who won
this.winner=this.curPlayer //winner is current player
this.score[this.curPlayer]++ //adds +1 to score of whoever won
this.updateStatus() //announces who won
this.updateScore() //updates player score
}else if(!this.board.includes(null)){
this.updateStatus('draw')
}else{
this.changeCurPlayer()
this.updateStatus()
}
}

}

changeCurPlayer(){ //switch players turn
if(this.curPlayer==='X'){
this.curPlayer='O'
}else{
this.curPlayer='X'
}
}

checkWin(board){

const winningConditions = [
[0, 1, 2], [3, 4, 5], [6, 7, 8], //rows
[0, 3, 6], [1, 4, 7], [2, 5, 8], //columns
[0,4,8], [2,4,6]//diagonals
]

let win=false;

winningConditions.forEach((combo)=>{
if(
board[combo[0]]===board[combo[1]]&&
board[combo[1]]===board[combo[2]]&&
board[combo[0]] !=null
){
win=true
}
});
return win
}

updateStatus(status=''){ //updates status for handleCellClick function
if(status==='draw'){
this.status.textContent='It\'s a tie!' //If there is a draw show there is a tie
}else if(this.winner){
this.status.textContent=`Player ${this.winner} wins!` //Show who won
}else{
this.status.textContent=`It's player ${this.curPlayer}'s turn` //else, keep the game going and show next player
}
}

updateScore(){
this.playeronescore.textContent=this.score.X //updates score while updating status
this.playertwoscore.textContent=this.score.O //updates score while updating status
}

restartButton(){ //resets the game without reloading the page
this.board=Array(9).fill(null) //returns empty array for each celll
this.curPlayer='X'
this.winner=null
this.squares.forEach(square => {square.textContent = ''})//returns empty square
this.updateStatus()
}

}
//Start Game
const game=new Game()
game.init()







172 changes: 172 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
body {
font-family:'Rock Salt', 'Permanent Marker';
color: #000000;
font-weight:bold ;

h1{
font-size: 30px;
text-align: center;
letter-spacing: 0.4em;
font-family:'Permanent Marker';
font-size: 40px;
margin:10px
}

h2{
border-bottom:2px solid black;
text-align: center;
border:4px solid black;
letter-spacing: 0.3em;
}

#board {
margin-left: auto;
margin-right: auto;
margin-bottom:20px;
width: 375px;
height: 375px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 5px;
}

.square {
width: 120px;
height: 120px;
border: 1px solid black;
background-color: #F5F5F5;
color:black;
font-family: 'Permanent Marker';
font-size: 40px;
display: flex;
justify-content: center;
align-items: center;
cursor:pointer
}

.square:hover {
background-color: pink;
}

.score{
display: flex;
flex-direction: column;
align-items: center;
}

tr{
display: flex;
justify-content: space-evenly;
font-size: 20px;
}

td{
margin: 0 50px 4px 50px;
}

th{
margin: 0 20px 4px 20px;
}

th,td{

font-family: 'Permanent Marker';
font-size: 20px;
}

#playeronescore,#playertwoscore{
border:2px solid black;
text-align: center;
padding:7px
}

#restartButton {
display: block;
margin-left: auto;
margin-right: auto;
height: 50px;
width: 150px;
background-color: black;
border: 1px solid #000000;
border-radius: 40px;
font-size: 20px;
font-family: 'Permanent Marker';
color:white;
letter-spacing: 0.1em;
text-align: center;
cursor:pointer
}

#restartButton:hover {
background-color:pink;
color: black;
}

#status{
font-family: 'Permanent Marker';
font-size: 15px;
color:rgb(248, 119, 141);
text-align: center;
padding:10px;
letter-spacing: 0.1em;
}

@media screen and (max-width: 480px) {
#board {
max-width: 300px;
grid-gap: 3px;
}

.square {
font-size: 30px;
}

#restartButton {
font-size: 16px;
padding: 8px 16px;
}

#status {
font-size: 18px;
}
}

@media screen and (min-width: 481px) and (max-width: 768px) {
#board {
max-width: 350px;
grid-gap: 4px;
}

.square {
font-size: 35px;
}

#restartButton {
font-size: 18px;
padding: 10px 20px;
}

#status {
font-size: 20px;
}
}

@media screen and (min-width: 769px) {
#board {
max-width: 400px;
grid-gap: 5px;
}

.square {
font-size: 45px;
}

#restartButton {
font-size: 20px;
padding: 12px 24px;
}

#status {
font-size: 22px;
}
}