DEV Community

Cover image for The Easy Way To Build A Tic Tac Toe Game!
Helitha Rupasinghe
Helitha Rupasinghe

Posted on • Edited on

The Easy Way To Build A Tic Tac Toe Game!

What Is Svelte?

Svelte is a radical new approach to building user interfaces with less code. No more complex state management libraries โ€” Svelte brings reactivity to JavaScript itself.

In this tutorial, you'll need basic understanding of HTML, CSS and JavaScript to build your own Tic Tac Toe Game with Svelte.

Getting Started

Go ahead and initialise our new project with the following command:

# Creating a new project
npx degit sveltejs/template 

# Install the dependencies...
npm install
Enter fullscreen mode Exit fullscreen mode

...then start Rollup.

# Npm Command
npm run dev 
Enter fullscreen mode Exit fullscreen mode

Navigate to localhost:8080 and you should see your app running. Edit a component file in src, save it, and reload the page to see your changes.

Basic Structure

Components in Svelte are written use .svelte files which contain HTML, CSS and JavaScript. Now let's create our Board.svelte file and modify our App.svelte file with the following structure.

<script>
<!-- JavaScript Logic -->
</script>

<style>
<!-- CSS Styles -->
</style>

<div>
<!-- HTML Markup -->
</div>
Enter fullscreen mode Exit fullscreen mode

Before we get started let's replace our main.js with the following:

import App from './App.svelte'

const app = new App({
  target: document.body,
})

export default app
Enter fullscreen mode Exit fullscreen mode

Our App Component

Now we will edit the App.svelte with the following to complete our App Component.

<script>
  import Board from "./Board.svelte";
</script>

<div class="app">
<div class ="container">
<Board />
</div>
 </div>

Enter fullscreen mode Exit fullscreen mode

Here we've imported Board.svelte and initalised our Board Component in App.svelte using HTML Markup.

Our Board Component

We'll open up Board.svelte and implement the JavaScript Logic for our Board Component.

<script>
  let userTurn = "X";
  let squares = new Array(9).fill(null);
  let winner = null;
  function restartGame() {
    userTurn = "X";
    squares = new Array(9).fill(null);
    winner = null;
  }
  function handleClick(i) {
    if (!squares[i] && !winner) {
      squares[i] = userTurn;
      switchTurn();
      winner = calculateWinner(squares);
      if (winner) userTurn = null;
    }
  }
  function switchTurn() {
    if (userTurn === "X") userTurn = "O";
    else userTurn = "X";
  }
  function calculateWinner(squares) {
    const winningCombinations = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6]
    ];
    for (let i = 0; i < winningCombinations.length; i++) {
      const [a, b, c] = winningCombinations[i];
      if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c])
        return `Winner: ${squares[a].toUpperCase()}`;
    }
    const isDraw = squares.every(square => square !== null);
    return isDraw ? "It's a draw" : null;
  }
</script>
Enter fullscreen mode Exit fullscreen mode

Now we can implement the HTML Markup for our Board.svelte component.

<div>
{#if winner}
  <h1>{winner}</h1>
  <button class="restart" on:click={restartGame}>Restart Game</button>
{:else}
  <h1>Next Player : {userTurn}</h1>
{/if}
</div>
<div class={userTurn != null ? userTurn + ' board' : 'board'}>
  {#each squares as square, i}
    <div
      class={square != null ? square + ' cell' : 'cell'}
      on:click={() => handleClick(i)} />
  {/each}
</div>
Enter fullscreen mode Exit fullscreen mode

Next step is to add the following styles to complete our Board.Svelte file.

<style>
    :root {
      --cell-size: 100px;
      --mark-size: calc(var(--cell-size) * 0.5);
    }
    .board {
      display: grid;
      justify-content: center;
      justify-items: center;
      align-content: center;
      align-items: center;
      grid-template-columns: repeat(3, auto);
    }
    .cell {
      width: var(--cell-size);
      height: var(--cell-size);
      border: 1px solid black;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
      cursor: pointer;
    }
    .cell:first-child,
    .cell:nth-child(2),
    .cell:nth-child(3) {
      border-top: none;
    }
    .cell:nth-child(3n + 1) {
      border-left: none;
    }
    .cell:nth-child(3n + 3) {
      border-right: none;
    }
    .cell:last-child,
    .cell:nth-child(8),
    .cell:nth-child(7) {
      border-bottom: none;
    }
    .cell.X,
    .cell.O {
      cursor: not-allowed;
    }
    .cell.X::before,
    .cell.X::after,
    .cell.O::before {
      background-color: black;
    }
    .board.X .cell:not(.X):not(.O):hover::before,
    .board.X .cell:not(.X):not(.O):hover::after,
    .board.O .cell:not(.X):not(.O):hover::before {
      background-color: lightgrey;
    }
    .cell.X::before,
    .cell.X::after,
    .board.X .cell:not(.X):not(.O):hover::before,
    .board.X .cell:not(.X):not(.O):hover::after {
      content: "";
      position: absolute;
      width: calc(var(--mark-size) * 0.15);
      height: var(--mark-size);
    }
    .cell.X::before,
    .board.X .cell:not(.X):not(.O):hover::before {
      transform: rotate(45deg);
    }
    .cell.X::after,
    .board.X .cell:not(.X):not(.O):hover::after {
      transform: rotate(-45deg);
    }
    .cell.O::before,
    .cell.O::after,
    .board.O .cell:not(.X):not(.O):hover::before,
    .board.O .cell:not(.X):not(.O):hover::after {
      content: "";
      position: absolute;
      border-radius: 50%;
    }
    .cell.O::before,
    .board.O .cell:not(.X):not(.O):hover::before {
      width: var(--mark-size);
      height: var(--mark-size);
    }
    .cell.O::after,
    .board.O .cell:not(.X):not(.O):hover::after {
      width: calc(var(--mark-size) * 0.7);
      height: calc(var(--mark-size) * 0.7);
      background-color: white;
    }
    h1 {
      text-align: center;
      text-decoration: underline;
      text-decoration-color: red;
      margin: 2rem;
      padding: 1rem;
    }
    .restart {
      font-weight: bold;
      position: absolute;
      top: 50%;
      padding: 20px;
      margin: 200px 500px;
    }
</style>
Enter fullscreen mode Exit fullscreen mode

Note ๐Ÿ’ก - You should now have a complete Tic Tac Toe game using Svelte.

Winner

Cool! Now if you made it this far, then I am linking the code to my Sandbox for you to fork or clone and then the job's done.

License: ๐Ÿ“

This project is under the MIT License (MIT). See the LICENSE for more information.

Contributions

Contributions are always welcome...

  • Fork the repository
  • Improve current program by
  • improving functionality
  • adding a new feature
  • bug fixes
  • Push your work and Create a Pull Request

Useful Resources

Top comments (2)

Collapse
 
andrewbaisden profile image
Andrew Baisden

Cool I found this interesting because I have not used Svelte yet.

Collapse
 
hr21don profile image
Helitha Rupasinghe

I can't wait for you to get started with svelte. ๐Ÿ’–