# TypeScript Adventure: Conquering the Second Boss

---

Welcome, TypeScript adventurers, to Level 5 of our journey! You've made it this far, and now it's time to face the second boss challenge. We're going to put our newfound knowledge of functions and types to the test by creating an exciting Pixel Match Game. Let's dive in!

## Prerequisites

Before we begin, make sure you're comfortable with JavaScript basics and have completed the previous levels. If you need to set up your development environment, check out the first blog for the tools you'll need to install.

## The Pixel Match Game Challenge

Our second boss challenge is to create a game where players need to color specific pixels to match a given pattern within a time limit. We'll be using TypeScript, HTML, and CSS to bring this game to life.

### What You'll Learn

* Practical application of functions and types
    
* Compiling and running a TypeScript project
    
* Interacting with HTML and CSS from TypeScript
    

### Step 1: Set up the project

1. Create a new directory for your project and navigate into it:
    
    * Open your terminal or command prompt.
        
    * Use the `mkdir` command followed by the project name to create a new directory, e.g., `mkdir pixel-match-game`.
        
    * Use the `cd` command followed by the project name to navigate into the newly created directory, e.g., `cd pixel-match-game`.
        

```bash
mkdir pixel-match-game
cd pixel-match-game
```

2. Initialize a new TypeScript project:
    

* Run `npm init -y` to initialize a new Node.js project with default settings.
    
    * This command creates a package.json file that contains information about your project and its dependencies.
        
* Run `npm install typescript --save-dev` to install TypeScript as a development dependency.
    
    * TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
        
* Run `npx tsc --init` to create a default TypeScript configuration file named `tsconfig.json`.
    
    * This file specifies the compiler options for your TypeScript project.
        
    * You will need to update the tsconfig.json target to `es2017` or later for this Boss fight.
        

```bash
npm init -y
npm install typescript --save-dev
npx tsc --init
```

3. Create the project structure:
    

Create a new directory named `src` inside your project directory. This directory will contain the source code files for your game.

Inside the `src` directory, create three files: `index.html`, `style.css`, and `index.ts`.

```bash
mkdir src
touch src/index.html
touch src/style.css
touch src/index.ts
```

* The `index.html` file will contain the structure and layout of the game's user interface.
    
* The `style.css` file will contain the styles and visual properties for the game's appearance.
    
* The `index.ts` file will contain the game logic written in TypeScript, which will be compiled to JavaScript.
    

```bash
pixel-match-game/
├── src/
│   ├── index.html
│   ├── style.css
│   └── index.ts
├── package.json
└── tsconfig.json
```

### Step 2: Implement the game layout

1. Open the `src/index.html` file and copy the provided HTML code:
    

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Pixel Match Game</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div id="container">
    <div id="canvas"></div>
    <div id="targetPattern"></div>
    <div id="controls">
      <button id="startGame">Start Game</button>
      <div id="timer">Time: <span id="timeRemaining">0</span></div>
      <div id="score">Score: <span id="currentScore">0</span></div>
    </div>
  </div>
  <script src="index.js"></script>
</body>
</html>
```

This HTML code sets up the basic structure for the game, including a canvas for the pixel grid, a targetPattern area to display the target pattern, and controls for starting the game, displaying the timer, and showing the score.

**We will not be going step by step into the HTML or CSS code as part of this lesson. So please copy and paste the HTML and CSS code as-is.**

2. Next, open the `src/style.css` file and copy the provided CSS code:
    

```css
#container {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 50px;
}

#canvas {
  display: grid;
  grid-template-columns: repeat(8, 40px);
  grid-template-rows: repeat(8, 40px);
  gap: 2px;
  background-color: #ccc;
  padding: 2px;
}

#canvas button {
  width: 100%;
  height: 100%;
  border: none;
  background-color: #FFFFFF;
}

#targetPattern {
  display: grid;
  grid-template-columns: repeat(8, 20px);
  grid-template-rows: repeat(8, 20px);
  gap: 2px;
  margin-bottom: 20px;
}

#targetPattern div {
  background-color: #ccc;
}

#controls {
  margin-top: 20px;
  text-align: center;
}

#timer, #score {
  margin-top: 10px;
  font-size: 18px;
}
```

This CSS code styles the game elements, including the `container`, `canvas`, `target pattern`, and `controls`.

### Step 3: Implement the game logic

1. Open the `src/index.ts` file:
    

This code will declare the necessary types, variables, and arrays to store the game state, including pixels, target pattern, remaining time, score, and canvas buttons.

Now, let's go through the rest of the code step by step:

#### Declare variables

We first must declare a type for our game of type `Pixel` and also declare our local variables we will be using. They are as follows:

```typescript
type Pixel = {
    x: number;
    y: number;
    color: string;
  };
  
  let pixels: Pixel[] = [];
  let targetPattern: Pixel[] = [];
  let timeRemaining = 0;
  let score = 0;
  let isGameRunning = false;
  let startButton: HTMLButtonElement | null = null;
  let canvasButtons: HTMLButtonElement[] = [];
```

Let's break these variables down further:

We create a TypeScript `type` called `Pixel`. As we know a `type` in TypeScript is a way to define the shape or structure of an object or variable. In this case, the `Pixel` type is an `object` type with three properties:

* `x` of type `number`, which represents the column index of the pixel
    
* `y` of type `number`, which represents the row index of the pixel
    
* `color` of type `string`, which represents the color of the pixel (usually in hexadecimal format)
    

By defining this `Pixel` type, we can create objects that follow this structure and ensure `type safety` throughout our code.

```typescript
let pixels: Pixel[] = [];
let targetPattern: Pixel[] = [];
```

We then declare variables `pixels` and `targetPattern` as `arrays` of type `Pixel` objects. The type annotations `Pixel[]` indicate that these variables will hold `arrays` of objects that conform to the `Pixel` type we defined earlier.

* `pixels` is an empty `array` that will store the state of all pixels in the game.
    
* `targetPattern` is also an empty `array` that will store the target pattern the player needs to match.
    

```typescript
let timeRemaining = 0;
let score = 0;
let isGameRunning = false;
```

The above declared variables keep track of the game state:

* `timeRemaining` is a `number` that represents the remaining time in the game, initialized to `0`.
    
* `score` is a `number` that represents the player's score, also initialized to `0`.
    
* `isGameRunning` is a `boolean` that indicates whether the game is currently running or not, initially set to `false`.
    

You may have noticed we haven't declared `types` for these variables. In Typescript we don't always have to declare the type unless we want to enforce `type-safety`. We could improve the variables `type-safety` by forcefully setting their `types`.

```typescript
let startButton: HTMLButtonElement | null = null;
let canvasButtons: HTMLButtonElement[] = [];
```

The above declared variables are related to the game's UI elements:

* `startButton` is a variable that will hold a reference to the HTML button element used to start the game. Its type is `HTMLButtonElement | null`, which means it can either be an `HTMLButtonElement` object or `null`. It is initialized to `null`.
    
* `canvasButtons` is an empty `array` that will store references to the button elements representing each pixel on the canvas. Its type is `HTMLButtonElement[]`, indicating an array of HTMLButtonElement objects.
    

By declaring these variables and their types, we establish a clear structure for our game data and UI elements. TypeScript's type system will help catch any potential errors where we try to use these variables or objects in an incorrect way.

#### Create the canvas

The `createCanvas` function generates the pixel grid dynamically:

```typescript
function createCanvas(): void {
  const canvasSize = 8;
  const canvas = document.getElementById('canvas');

  for (let y = 0; y < canvasSize; y++) {
    for (let x = 0; x < canvasSize; x++) {
      const pixel: Pixel = { x, y, color: '#FFFFFF' };
      pixels.push(pixel);

      const pixelButton = createPixelButton(pixel);
      canvas?.appendChild(pixelButton);
    }
  }
}
```

Let's break this function down further:

```typescript
function createCanvas(): void {
  const canvasSize = 8;
  const canvas = document.getElementById('canvas');
```

We declare a function called `createCanvas` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to set up the canvas and pixel grid of the game to show the player.

Inside the function, we declare a constant `canvasSize` with a value of `8`, representing the size of the pixel grid `(8x8)`. We also retrieve the canvas element from the HTML document using `document.getElementById('canvas')`.

```typescript
for (let y = 0; y < canvasSize; y++) {
    for (let x = 0; x < canvasSize; x++) {
      const pixel: Pixel = { x, y, color: '#FFFFFF' };
      pixels.push(pixel);
```

Here, we use nested `for` loops to iterate over the rows (`y`) and columns (`x`) of the pixel grid. For each iteration, we create a `Pixel` object with the current `x` and `y` coordinates and a default color of `'#FFFFFF'` (white). The `Pixel` type is defined earlier in the code as:

```typescript
type Pixel = {
  x: number;
  y: number;
  color: string;
};
```

This `type` definition specifies that a `Pixel` object should have properties `x` (a number representing the column index), `y` (a number representing the row index), and `color` (a string representing the color in hexadecimal format). By creating a `Pixel` object for each grid cell, we can keep track of its coordinates and color state. The `pixel` object is then pushed into the `pixels` array, which stores the state of all pixels in the game.

```typescript
const pixelButton = createPixelButton(pixel);
      canvas?.appendChild(pixelButton);
    }
  }
}
```

After creating the `Pixel` object, we call the `createPixelButton` function (which we'll explain later) to create a `button` element for that pixel. The created `pixelButton` is then appended to the `canvas` element using `canvas?.appendChild(pixelButton)`. The optional chaining operator `?`. is used to check if canvas is not null before accessing its appendChild method.

By using the `Pixel` type and creating `Pixel` objects, we ensure that each pixel in the game has a consistent structure with well-defined properties.

This makes it easier to manage and manipulate the pixel data throughout the game logic. Additionally, TypeScript's type system helps catch errors during development if we try to use incorrect types or properties for the `Pixel` objects.

#### Create pixel buttons

The `createPixelButton` function creates a button element for each pixel and adds event listeners for coloring:

```typescript
function createPixelButton(pixel: Pixel): HTMLButtonElement {
  const pixelButton = document.createElement('button');
  pixelButton.style.backgroundColor = pixel.color;
  pixelButton.dataset.x = pixel.x.toString();
  pixelButton.dataset.y = pixel.y.toString();
  pixelButton.disabled = true;
  pixelButton.addEventListener('click', () => {
    const currentColor = pixel.color;
    const newColor = currentColor === '#FFFFFF' ? '#FF0000' : '#FFFFFF';
    pixel.color = newColor;
    pixelButton.style.backgroundColor = newColor;
    checkPattern();
  });
  canvasButtons.push(pixelButton);
  return pixelButton;
}
```

Let's break this function down further:

```typescript
function createPixelButton(pixel: Pixel): HTMLButtonElement {
```

We declares a function called `createPixelButton` that takes a `Pixel` object as a parameter and returns an `HTMLButtonElement`. The purpose of this function is to create a button element for each pixel in the game's grid.

```typescript
const pixelButton = document.createElement('button');
```

We declare a constant called `pixelButton` which creates a new HTML `<button>` element.

```typescript
pixelButton.style.backgroundColor = pixel.color;
pixelButton.dataset.x = pixel.x.toString();
pixelButton.dataset.y = pixel.y.toString();
pixelButton.disabled = true;
```

We continue by setting the initial properties of the `pixelButton` object:

* [`pixelButton.style`](http://pixelButton.style)`.backgroundColor` sets the background color of the button to the color of the pixel object.
    
* `pixelButton.dataset.x` and `pixelButton.dataset.y` set custom data attributes on the button element with the x and y coordinates of the pixel, respectively. These will be used later to identify which pixel the button represents.
    
* `pixelButton.disabled = true` initially disables the button, preventing the player from interacting with it until the game starts.
    

```typescript
pixelButton.addEventListener('click', () => {
    const currentColor = pixel.color;
    const newColor = currentColor === '#FFFFFF' ? '#FF0000' : '#FFFFFF';
    pixel.color = newColor;
    pixelButton.style.backgroundColor = newColor;
    checkPattern();
  });
```

We add a click event listener to the `pixelButton` object. When the button is clicked, the following code inside the event listener function will be executed:

* `const currentColor = pixel.color` stores the current color of the pixel object in the currentColor variable.
    
* `const newColor = currentColor === '#FFFFFF' ? '#FF0000' : '#FFFFFF'` determines the new color for the pixel. If the current color is white `(#FFFFFF)`, the new color will be red `(#FF0000)`; otherwise, the new color will be white `(#FFFFFF)`.
    
* `pixel.color = newColor` updates the color property of the `pixel` object with the new color.
    
* [`pixelButton.style`](http://pixelButton.style)`.backgroundColor = newColor` updates the background color of the button to match the new color of the pixel.
    
* `checkPattern()` calls a function (which will be implemented later) to check if the player's pattern matches the target pattern.
    

```typescript
canvasButtons.push(pixelButton);
  return pixelButton;
}
```

* `canvasButtons.push(pixelButton)` adds the created pixelButton to the canvasButtons array, which stores all the button elements for the pixels in the game.
    
* `return pixelButton` returns the created pixelButton element.
    

This function is responsible for creating a button element for each pixel in the game grid, setting its initial properties (color, coordinates, and disabled state), and adding a click event listener to toggle the color of the pixel between red and white. The created button is then added to the `canvasButtons` array and returned from the function.

#### Initialize the game

The `initializeGame` function sets up the initial state of the game:

```typescript
function initializeGame(): void {
  startButton = document.getElementById('startGame') as HTMLButtonElement | null;
  if (startButton) {
    startButton.addEventListener('click', startGame);
  }
  enableStartButton();
  disableCanvasButtons();
  clearTargetPattern();
}
```

Let's break the function down further:

```typescript
function initializeGame(): void {
```

We declare a function called `initializeGame` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to set up the initial state of the game when it first loads.

```typescript
startButton = document.getElementById('startGame') as HTMLButtonElement | null;
```

our `startButton` variable retrieves an HTML element with the ID `'startGame'` from the document and assigns it. The `as HTMLButtonElement | null` part is a `type assertion` in TypeScript, which tells the compiler that the element retrieved by `getElementById` can be either an `HTMLButtonElement` (if the element is found) or `null` (if the element is not found).

```typescript
if (startButton) {
    startButton.addEventListener('click', startGame);
  }
```

This above block of code checks if the `startButton` variable is not null (i.e., the element with the ID 'startGame' was found). If `startButton` is not null, it adds a click event listener to the `button` element. When the button is clicked, the `startGame` function (which will be implemented later) will be called to start the game.

```typescript
enableStartButton();
disableCanvasButtons();
clearTargetPattern();
}
```

We then call separate functions to set up the initial state of the game:

* `enableStartButton()` is a function (which will be implemented later) that enables the start button, allowing the player to click it and start the game.
    
* `disableCanvasButtons()` is a function (which will be implemented later) that disables all the buttons representing the pixels on the canvas, preventing the player from interacting with them until the game starts.
    
* `clearTargetPattern()` is a function (which will be implemented later) that clears the display area for the target pattern, ensuring that no pattern is shown initially.
    

The `initializeGame` function is responsible for setting up the initial state of the game UI, including retrieving the start button element, adding a click event listener to it, enabling the start button, disabling the canvas buttons, and clearing the target pattern display area.

#### Start the game

The `startGame` function initializes the game state, generates the target pattern, and starts the timer:

```typescript
function startGame(): void {
  if (isGameRunning) return;

  isGameRunning = true;
  timeRemaining = 30;
  score = 0;
  pixels.forEach(pixel => pixel.color = '#FFFFFF');
  targetPattern = generateTargetPattern();
  displayTargetPattern();
  updateTimer();
  updateScore();
  disableStartButton();
  enableCanvasButtons();
}
```

Let's break down this function:

```typescript
function startGame(): void {
```

We declare a function called `startGame` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to start the game and set up its initial state.

```typescript
if (isGameRunning) return;
```

This if statement checks if the i`sGameRunning` variable is `true`. If it is, the function immediately returns without executing any further code. This code is to prevent the game from starting multiple times simultaneously.

```typescript
isGameRunning = true;
timeRemaining = 30;
score = 0;
```

We then set the initial state for the game:

* `isGameRunning = true` sets the `isGameRunning` variable to `true`, indicating that the game is now running.
    
* `timeRemaining = 30` sets the initial value of the `timeRemaining` variable to `30`.
    
* `score = 0` resets the player's score to `0` at the start of the game.
    

```typescript
pixels.forEach(pixel => pixel.color = '#FFFFFF');
```

This line above iterates over the `pixels` array (which contains the state of all pixels in the game grid) and sets the `color` property of each pixel object to `'#FFFFFF'`, which is the hexadecimal code for the color `white`. This effectively resets the color of all pixels to white at the start of the game.

```typescript
targetPattern = generateTargetPattern();
  displayTargetPattern();
```

These lines above are responsible for generating and displaying the target pattern that the player needs to match:

* `targetPattern = generateTargetPattern()` calls the `generateTargetPattern` function (which will be implemented later) and assigns the result to the `targetPattern` variable.
    
* `displayTargetPattern()` calls a function (which will be implemented later) to render and display the target pattern on the game screen.
    

```typescript
updateTimer();
updateScore();
disableStartButton();
enableCanvasButtons();
}
```

These lines above call separate functions to update the timer and score displays on the game screen:

* `updateTimer()` is a function (which will be implemented later) that updates the display for the remaining time in the game.
    
* `updateScore()` is a function (which will be implemented later) that updates the display for the player's current score.
    
* `disableStartButton()` is a function (which will be implemented later) that disables the start button, preventing the player from starting the game again while it's already running.
    
* `enableCanvasButtons()` is a function (which will be implemented later) that enables all the buttons representing the pixels on the canvas, allowing the player to interact with them and start playing the game.
    

#### Generate the target pattern

The `generateTargetPattern` function generates a random target pattern of red pixels:

```typescript
function generateTargetPattern(): Pixel[] {
  const pattern: Pixel[] = [];
  const patternSize = Math.floor(Math.random() * 3) + 2;

  for (let i = 0; i < patternSize; i++) {
    const x = Math.floor(Math.random() * 8);
    const y = Math.floor(Math.random() * 8);
    const color = '#FF0000';
    pattern.push({ x, y, color });
  }

  return pattern;
}
```

Let's break down this function:

```typescript
function generateTargetPattern(): Pixel[] {
```

We declare a function called `generateTargetPattern` that returns an array of `Pixel` objects. The purpose of this function is to generate a random pattern of pixels that the player needs to match in the game.

```typescript
const pattern: Pixel[] = [];
```

We declare a constant variable `pattern` and initializes it as an empty `array` of `Pixel` objects. This array will store the generated target pattern.

```typescript
const patternSize = Math.floor(Math.random() * 3) + 2;
```

The line above calculates a random pattern size for the target pattern. The `Math.random()` function generates a random floating-point number between `0` and `1`. Multiplying it by `3` gives a random number between `0` and `3`. Then, `Math.floor` rounds down the result to the nearest integer. Finally, adding `2` to the result ensures that the `patternSize` will be a random integer between `2` and `4` (inclusive).

```typescript
for (let i = 0; i < patternSize; i++) {
    const x = Math.floor(Math.random() * 8);
    const y = Math.floor(Math.random() * 8);
    const color = '#FF0000';
    pattern.push({ x, y, color });
  }
```

The `for` loop iterates `patternSize` number of times to generate the individual pixels that make up the target pattern:

* `const x = Math.floor(Math.random() * 8)` generates a random integer between `0` and `7` (inclusive), representing the column index (x-coordinate) of the pixel.
    
* `const y = Math.floor(Math.random() * 8)` generates a random integer between `0` and `7` (inclusive), representing the row index (y-coordinate) of the pixel.
    
* `const color = '#FF0000'` sets the color of the pixel to the hexadecimal code for the color red `(#FF0000)`.
    
* `pattern.push({ x, y, color })` creates a new `Pixel` object with the generated `x`, `y`, and color values, and adds it to the `pattern` array using the `push` method.
    

```typescript
return pattern;
}
```

Finally, the line above returns the `pattern` array containing the randomly generated `Pixel` objects that represent the target pattern for the game.

#### Display the target pattern

The `displayTargetPattern` function renders the target pattern on the game screen:

```typescript
function displayTargetPattern(): void {
  const targetPatternElement = document.getElementById('targetPattern');
  if (targetPatternElement) {
    targetPatternElement.innerHTML = '';
    for (let y = 0; y < 8; y++) {
      for (let x = 0; x < 8; x++) {
        const cell = document.createElement('div');
        const targetPixel = targetPattern.find(pixel => pixel.x === x && pixel.y === y);
        if (targetPixel) {
          cell.style.backgroundColor = targetPixel.color;
        }
        targetPatternElement.appendChild(cell);
      }
    }
  }
}
```

Let's break down this function:

```typescript
function displayTargetPattern(): void {
```

We declare a function called `displayTargetPattern` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to render and display the target pattern on the game screen for the player to match.

```typescript
const targetPatternElement = document.getElementById('targetPattern');
```

The line above retrieves an HTML element with the ID `'targetPattern'` from the document and assigns it to the `targetPatternElement` variable. This element is a `container` where the target pattern will be displayed.

```typescript
if (targetPatternElement) {
    targetPatternElement.innerHTML = '';
```

This `if` statement checks if the `targetPatternElement` variable is not null (i.e., the element with the ID `'targetPattern'` was found). If it's not null, the code inside the block will be executed. The line `targetPatternElement.innerHTML = ''` clears the inner HTML content of the `targetPatternElement`, effectively removing any previous content from the target pattern display area.

```typescript
for (let y = 0; y < 8; y++) {
      for (let x = 0; x < 8; x++) {
        const cell = document.createElement('div');
        const targetPixel = targetPattern.find(pixel => pixel.x === x && pixel.y === y);
        if (targetPixel) {
          cell.style.backgroundColor = targetPixel.color;
        }
        targetPatternElement.appendChild(cell);
      }
    }
  }
}
```

These nested `for` loops iterate over the rows (`y`) and columns (`x`) of an `8x8` grid, representing the pixels in the target pattern:

* `const cell = document.createElement('div')` creates a new `<div>` element for each cell in the grid.
    
* `const targetPixel = targetPattern.find(pixel => pixel.x === x && pixel.y === y)` searches the `targetPattern` array for a `Pixel` object with the current `x` and `y` coordinates. If a matching `Pixel` object is found, it is assigned to the `targetPixel` variable; otherwise, `targetPixel` will be `undefined`.
    
* `if (targetPixel) {` [`cell.style`](http://cell.style)`.backgroundColor = targetPixel.color; }` checks if `targetPixel` is not `undefined`. If it's not, the `backgroundColor` style of the cell element is set to the color property of the `targetPixel` object.
    
* `targetPatternElement.appendChild(cell)` appends the cell element as a child of the `targetPatternElement`, effectively rendering it on the game screen.
    

The nested loops create a grid of `<div>` elements, where each element represents a pixel in the target pattern. The background color of each `<div>` element is set to red `(#FF0000)` if there is a corresponding `Pixel` object in the `targetPattern` array with the same coordinates; otherwise, the background color remains the default color white `(#FFFFFF)`.

#### Check the pattern

The `checkPattern` function compares the player's pattern with the target pattern and updates the score if a match is found:

```typescript
function checkPattern(): void {
  const isMatch = targetPattern.every(targetPixel => {
    const playerPixel = pixels.find(pixel =>
      pixel.x === targetPixel.x && pixel.y === targetPixel.y
    );
    return playerPixel?.color === targetPixel.color;
  });

  if (isMatch) {
    score++;
    targetPattern = generateTargetPattern();
    displayTargetPattern();
    updateScore();
    resetGrid(); // Reset the grid after a correct guess
  }
}
```

Let's break the function down further:

```typescript
function checkPattern(): void {
```

We declare a function called `checkPattern` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to check if the player's pattern matches the target pattern and update the game state accordingly.

```typescript
const isMatch = targetPattern.every(targetPixel => {
    const playerPixel = pixels.find(pixel =>
      pixel.x === targetPixel.x && pixel.y === targetPixel.y
    );
    return playerPixel?.color === targetPixel.color;
  });
```

The code above declares a constant variable `isMatch` and assigns it the result of the `every` method called on the `targetPattern` array. The `every` method is a built-in JavaScript array method that tests whether all elements in the array pass a certain condition. In this case, the condition is defined by the arrow function `targetPixel => { ... }`.

For each `targetPixel` in the `targetPattern` array: - `const playerPixel = pixels.find(pixel => pixel.x === targetPixel.x && pixel.y === targetPixel.y)` searches the `pixels` array (which contains the player's current pattern) for a `Pixel` object with the same `x` and `y` coordinates as the `targetPixel`. If a matching `Pixel` object is found, it is assigned to the `playerPixel` variable; otherwise, `playerPixel` will be `undefined`. - `return playerPixel?.color === targetPixel.color` checks if the color property of the `playerPixel` (if it exists, hence the optional chaining `?`.) is equal to the color property of the `targetPixel`. This expression returns `true` if the colors match, and `false` otherwise.

The `every` method will return `true` if the expression `playerPixel?.color === targetPixel.color` is `true` for all `targetPixel` objects in the `targetPattern` array. In other words, `isMatch` will be `true` if the player's pattern (represented by the `pixels` array) matches the target pattern exactly.

```typescript
if (isMatch) {
    score++;
    targetPattern = generateTargetPattern();
    displayTargetPattern();
    updateScore();
    resetGrid(); // Reset the grid after a correct guess
  }
```

This `if` statement is executed if `isMatch` is `true`, meaning the player's pattern matches the target pattern:

* `score++` increments the player's score by `1`.
    
* `targetPattern = generateTargetPattern()` generates a new target pattern by calling the `generateTargetPattern` function and assigns the result to the `targetPattern` variable.
    
* `displayTargetPattern()` renders the new target pattern on the game screen by calling the `displayTargetPattern` function.
    
* `updateScore()` updates the score display on the game screen by calling the `updateScore` function.
    
* `resetGrid()` resets the game grid to its initial state by calling the `resetGrid` function. This is done to clear the player's previous pattern and prepare for the next round.
    

#### Reset the grid

The `resetGrid` function resets the pixel colors to white and updates the canvas:

```typescript
function resetGrid(): void {
  pixels.forEach(pixel => pixel.color = '#FFFFFF');
  updateCanvas();
}
```

Let's break this function down further:

```typescript
function resetGrid(): void {
```

We declare a function called `resetGrid` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to reset the game grid to its initial state.

```typescript
pixels.forEach(pixel => pixel.color = '#FFFFFF');
```

This code above uses the `forEach` method to iterate over the `pixels` array, which contains the state of all pixels in the game grid. For each `pixel` in the `pixels` array, the expression `pixel.color = '#FFFFFF'` is executed. This line sets the color property of the pixel object to the hexadecimal value `'#FFFFFF'`, which represents the color white. By setting the color of all pixels in the `pixels` array to white, we effectively reset the visual state of the game grid, clearing any previously colored pixels.

```typescript
updateCanvas();
}
```

This code above calls the `updateCanvas` function, which is responsible for updating the visual representation of the game grid on the screen based on the state stored in the `pixels` array. While the previous line `(pixels.forEach(pixel => pixel.color = '#FFFFFF'))` updates the `pixels` array by setting all pixels to white, the `updateCanvas` function is responsible for reflecting these changes in the actual user interface (UI) by rendering the updated pixel colors on the game grid to the user.

#### Update the Canvas

The `updateCanvas` function updates the grid on player click to the colour red.

```typescript
function updateCanvas(): void {
  pixels.forEach(pixel => {
    const pixelButton = document.querySelector(`#canvas button[data-x="${pixel.x}"][data-y="${pixel.y}"]`) as HTMLButtonElement;
    if (pixelButton) {
      pixelButton.style.backgroundColor = pixel.color;
    }
  });
}
```

Let's break this function down further:

```typescript
function updateCanvas(): void {
```

We declare a function called `updateCanvas` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to update the visual representation of the game grid on the screen based on the current state of the `pixels` array.

```typescript
pixels.forEach(pixel => {
    const pixelButton = document.querySelector(`#canvas button[data-x="${pixel.x}"][data-y="${pixel.y}"]`) as HTMLButtonElement;
```

This code above uses the `forEach` method to iterate over the `pixels` array, which contains the state of all pixels in the game grid. For each `pixel` in the `pixels` array, the following code is executed:

* `const pixelButton = document.querySelector(#canvas button[data-x="${pixel.x}"][data-y="${pixel.y}"]) as HTMLButtonElement`; selects an HTML button element from the document that represents the current pixel. The `document.querySelector` function uses a `CSS` selector to find the button element with the following criteria:
    
    * It is a descendant of an element with the ID `'canvas'`.
        
    * It is a `<button>` element.
        
    * It has a `data-x` attribute value that matches the `x` coordinate of the current pixel.
        
    * It has a `data-y` attribute value that matches the `y` coordinate of the current pixel.
        
* The `as HTMLButtonElement` part is a `type assertion` in TypeScript, which tells the compiler that the element returned by `document.querySelector` should be treated as an `HTMLButtonElement` (a button element).
    

```typescript
if (pixelButton) {
      pixelButton.style.backgroundColor = pixel.color;
    }
  });
}
```

This `if` statement checks if the `pixelButton` variable is not null (i.e., a button element was found for the current pixel). If `pixelButton` is not null, the code inside the block is executed:

* [`pixelButton.style`](http://pixelButton.style)`.backgroundColor = pixel.color` sets the `backgroundColor` style property of the `pixelButton` element to the value of the color property of the current pixel object.
    

By iterating over the `pixels` array and updating the `backgroundColor` of the corresponding button elements based on the color property of each pixel, this function updates the visual representation of the game grid on the screen to match the current state stored in the `pixels` array.

### Update the timer

The `updateTimer` function updates the remaining time and ends the game if the time runs out:

```typescript
typescriptCopyfunction updateTimer(): void {
  const timerElement = document.getElementById('timeRemaining');
  if (timerElement) {
    timerElement.textContent = timeRemaining.toString();
  }

  if (timeRemaining > 0) {
    timeRemaining--;
    setTimeout(updateTimer, 1000);
  } else {
    endGame();
    isGameRunning = false;
    enableStartButton();
  }
}
```

Let's break this function down further:

```typescript
function updateTimer(): void {
```

We declare a function called `updateTimer` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to update the timer display and handle the end of the game when the time runs out.

```typescript
const timerElement = document.getElementById('timeRemaining');
```

The code above retrieves an HTML element with the ID `'timeRemaining'` from the document and assigns it to the `timerElement` variable. This element is a `container` where the remaining time will be displayed.

```typescript
if (timerElement) {
    timerElement.textContent = timeRemaining.toString();
  }
```

This `if` statement checks if the `timerElement` variable is not null (i.e., the element with the ID `'timeRemaining'` was found). If it's not null, the code inside the block is executed:

* `timerElement.textContent = timeRemaining.toString()` sets the text content of the `timerElement` to the string representation of the `timeRemaining` value. This displays the remaining time on the screen.
    

```typescript
if (timeRemaining > 0) {
    timeRemaining--;
    setTimeout(updateTimer, 1000);
  } else {
    endGame();
    isGameRunning = false;
    enableStartButton();
  }
```

This `if...else` statement checks the value of the `timeRemaining` variable:

* If `timeRemaining` is greater than 0:
    
    * `timeRemaining--` decrements the timeRemaining value by `1`.
        
    * `setTimeout(updateTimer, 1000)` sets a timeout to call the `updateTimer` function again after `1000` milliseconds (1 second). This creates a recurring loop that updates the timer every second.
        
* If `timeRemaining` is `0` or less:
    
    * `endGame()` calls the `endGame` function, which handles the end of the game scenario.
        
    * `isGameRunning = false` sets the `isGameRunning` variable to `false`, indicating that the game is no longer running.
        
    * `enableStartButton()` calls the `enableStartButton` function, which enables the start button, allowing the player to start a new game.
        

#### Update the score

The `updateScore` function updates the score display:

```typescript
function updateScore(): void {
  const scoreElement = document.getElementById('currentScore');
  if (scoreElement) {
    scoreElement.textContent = score.toString();
  }
}
```

Let's break this function down further:

```typescript
function updateScore(): void {
```

We declare a function called `updateScore` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to update the score display on the game screen.

```typescript
const scoreElement = document.getElementById('currentScore');
```

The code above retrieves an HTML element with the ID `'currentScore'` from the document and assigns it to the `scoreElement` variable. This element is a `container` where the player's current score will be displayed.

```typescript
if (scoreElement) {
    scoreElement.textContent = score.toString();
  }
```

This `if` statement checks if the `scoreElement` variable is not null (i.e., the element with the ID `'currentScore'` was found). If it's not null, the code inside the block is executed:

* `scoreElement.textContent = score.toString()` sets the text content of the `scoreElement` to the string representation of the score value. This displays the player's current score on the screen.
    

#### Clear the target pattern

The `clearTargetPattern` function clears the target pattern display:

```typescript
function clearTargetPattern(): void {
  const targetPatternElement = document.getElementById('targetPattern');
  if (targetPatternElement) {
    targetPatternElement.innerHTML = '';
  }
}
```

Let's break this function down further:

```typescript
function clearTargetPattern(): void {
```

We declare a function called `clearTargetPattern` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to clear the target pattern display area on the game screen.

```typescript
const targetPatternElement = document.getElementById('targetPattern');
```

The code above retrieves an HTML element with the ID `'targetPattern'` from the document and assigns it to the `targetPatternElement` variable. This element is a `container` where the target pattern is displayed on the game screen.

```typescript
if (targetPatternElement) {
    targetPatternElement.innerHTML = '';
  }
```

This `if` statement checks if the `targetPatternElement` variable is not null (i.e., the element with the ID `'targetPattern'` was found). If it's not null, the code inside the block is executed:

* `targetPatternElement.innerHTML = ''` sets the inner HTML content of the `targetPatternElement` to an empty string. This effectively removes any existing content (e.g., HTML elements representing the target pattern) from the target pattern display area.
    

#### Reset the game

The `resetGame` function resets the game state to its initial values:

```typescript
function resetGame(): void {
  resetGrid();
  targetPattern = [];
  score = 0;
  timeRemaining = 30;
  updateScore();
  clearTargetPattern();
  enableStartButton();
  disableCanvasButtons();
}
```

Let's break this function down further:

```typescript
function resetGame(): void {
```

We declare a function called `resetGame` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to reset the game state to its initial conditions, effectively starting a new game.

```typescript
resetGrid();
```

The code above calls the `resetGrid` function, which is responsible for resetting the game grid to its initial state. This involves clearing all colored pixels and resetting the colors to the default value (e.g., white).

```typescript
targetPattern = [];
```

This code above resets the `targetPattern` array to an empty array (`[]`). The `targetPattern` array stores the target pattern that the player needs to match in the game.

```typescript
score = 0;
```

This code above resets the score variable to `0`. The score variable keeps track of the player's score in the game.

```typescript
timeRemaining = 30;
```

This code above sets the `timeRemaining` variable to `30`. The `timeRemaining` variable represents the time remaining for the player to complete the game.

```typescript
updateScore();
clearTargetPattern();
enableStartButton();
disableCanvasButtons();
}
```

The code above does the following:

* Calls `updateScore` function to update the score display on the game screen to `0`.
    
* Calls `clearTargetPattern` function to clear the target pattern display area on the game screen.
    
* Calls `enableStartButton` function to enable the start button, allowing the player to start a new game.
    
* Calls `disableCanvasButtons` function to disable the input controls or buttons on the game canvas or grid.
    

#### End the game

The `endGame` function handles the end of the game, displaying the final score and allowing the player to play again:

```typescript
function endGame(): void {
  const playAgain = confirm(`Game Over! Your score: ${score}\nDo you want to play again?`);
  if (playAgain) {
    resetGame();
  } else {
    isGameRunning = false;
    enableStartButton();
    disableCanvasButtons();
    clearTargetPattern();
  }
}
```

Let's break this function down further:

```typescript
function endGame(): void {
```

We declare a function called `endGame` that doesn't return any value (indicated by the `void` return type). The purpose of this function is to handle the end of the game scenario, displaying the final score and providing an option for the player to start a new game or exit.

```typescript
const playAgain = confirm(`Game Over! Your score: ${score}\nDo you want to play again?`);
```

This code above displays a `modal` dialog box with the message `"Game Over! Your score: [current score value]" followed by a newline character \n` and the question `"Do you want to play again?"`. The `confirm` function returns a `boolean` value (`true` if the user clicks `"OK"` or `false` if the user clicks `"Cancel"`). The returned value is stored in the `playAgain` constant.

```typescript
if (playAgain) {
    resetGame();
  } else {
    isGameRunning = false;
    enableStartButton();
    disableCanvasButtons();
    clearTargetPattern();
  }
}
```

The `if...else` statement checks the value of the `playAgain` constant:

* If `playAgain` is `true` (i.e., the user clicked `"OK"` in the dialog box):
    
    * `resetGame()` is called, which resets the game state and starts a new game.
        
* If `playAgain` is `false` (i.e., the user clicked `"Cancel"` in the dialog box):
    
    * `isGameRunning = false` sets the `isGameRunning` variable to `false`, indicating that the game is no longer running.
        
    * `enableStartButton()` is called, which enables the start button, allowing the player to start a new game if they change their mind.
        
    * `disableCanvasButtons()` is called, which disables the buttons or input controls on the game canvas or grid, preventing further interaction.
        
    * `clearTargetPattern()` is called, which clears the target pattern display area on the game screen.
        

#### Enable/disable buttons

These `functions` handle enabling and disabling the start and canvas buttons, this is to stop the player clicking on the canvas or the start button multiple times before the game starts:

```typescript
function disableStartButton(): void {
  startButton = document.getElementById('startGame') as HTMLButtonElement | null;
  if (startButton) {
    startButton.disabled = true;
  }
}

function enableStartButton(): void {
  if (startButton) {
    startButton.disabled = false;
  }
}

function disableCanvasButtons(): void {
  canvasButtons.forEach(button => button.disabled = true);
}

function enableCanvasButtons(): void {
  canvasButtons.forEach(button => button.disabled = false);
}
```

Let's break down these functions further:

```typescript
function disableStartButton(): void {
  startButton = document.getElementById('startGame') as HTMLButtonElement | null;
  if (startButton) {
    startButton.disabled = true;
  }
}
```

This function is responsible for disabling the start button on the game screen:

* `startButton = document.getElementById('startGame') as HTMLButtonElement | null;` retrieves the HTML element with the ID `'startGame'` from the document and assigns it to the `startButton` variable. The `as HTMLButtonElement | null` is a `type assertion` in TypeScript, indicating that the element can be either an `HTMLButtonElement` (a button element) or `null` (if the element is not found).
    
* `if (startButton) { startButton.disabled = true; }` checks if the `startButton` variable is not null. If it's not null, it sets the disabled property of the button element to `true`, effectively disabling the button and preventing user interaction.
    

```typescript
function enableStartButton(): void {
  if (startButton) {
    startButton.disabled = false;
  }
}
```

This function is responsible for enabling the start button on the game screen:

* `if (startButton) { startButton.disabled = false; }` checks if the `startButton` variable is not null. If it's not null, it sets the disabled property of the button element to `false`, effectively enabling the button and allowing user interaction.
    

```typescript
function disableCanvasButtons(): void {
  canvasButtons.forEach(button => button.disabled = true);
}
```

This function is responsible for disabling the buttons or input controls on the game canvas or grid:

* `canvasButtons.forEach(button => button.disabled = true);` iterates over the `canvasButtons` array, which contains references to the button elements representing each pixel on the game canvas. For each `button` element in the array, it sets the disabled property to `true`, effectively `disabling` the button and `preventing` user interaction.
    

```typescript
function enableCanvasButtons(): void {
  canvasButtons.forEach(button => button.disabled = false);
}
```

This function is responsible for enabling the buttons or input controls on the game canvas or grid:

* `canvasButtons.forEach(button => button.disabled = false);` iterates over the `canvasButtons` array, which contains references to the button elements representing each pixel on the game canvas. For each `button` element in the array, it sets the disabled property to `false`, effectively `enabling` the button and `allowing` user interaction.
    

#### Initialize the game

Finally, the `createCanvas` function is called to generate the initial pixel grid, and the `initializeGame` function is called to set up the game:

```typescript
createCanvas();
initializeGame();

startButton = document.getElementById('startGame') as HTMLButtonElement | null;
if (startButton) {
  startButton.addEventListener('click', startGame);
}
```

Let's break this last bit of the code down further:

```typescript
createCanvas();
initializeGame();
```

The code above calls the `createCanvas` and `initializeGame` functions, respectively.

* `createCanvas()` is responsible for generating the pixel grid on the game screen. It creates `button` elements for each pixel and appends them to the canvas `container`.
    
* `initializeGame()` is responsible for setting up the initial state of the game. This includes retrieving the start button element, adding an event listener to it, enabling/disabling buttons, and clearing the target pattern display area.
    

```typescript
startButton = document.getElementById('startGame') as HTMLButtonElement | null;
```

This code above retrieves the HTML element with the ID `'startGame'` from the document and assigns it to the `startButton` variable. The `as HTMLButtonElement | null` is a `type assertion` in TypeScript, indicating that the element can be either an `HTMLButtonElement` (a button element) or `null` (if the element is not found).

```typescript
if (startButton) {
  startButton.addEventListener('click', startGame);
}
```

This `if` statement checks if the `startButton` variable is not null. If it's not null, it means the start button element was found on the page. In that case, the code inside the block is executed:

* `startButton.addEventListener('click', startGame)` adds a click event listener to the start button. When the button is clicked, the `startGame` function will be called. The `startGame` function is responsible for starting the game and setting up the necessary game state and logic.
    

By adding the event listener to the start button, the player can initiate the game by clicking the button. The `startGame` function will be executed when the button is clicked, kicking off the game logic and updating the game state accordingly.

#### Complete Typescript Code for `src/index.ts`

```typescript
type Pixel = {
    x: number;
    y: number;
    color: string;
  };
  
  let pixels: Pixel[] = [];
  let targetPattern: Pixel[] = [];
  let timeRemaining = 0;
  let score = 0;
  let isGameRunning = false;
  let startButton: HTMLButtonElement | null = null;
  let canvasButtons: HTMLButtonElement[] = [];
  
  function createCanvas(): void {
    const canvasSize = 8;
    const canvas = document.getElementById('canvas');
  
    for (let y = 0; y < canvasSize; y++) {
      for (let x = 0; x < canvasSize; x++) {
        const pixel: Pixel = { x, y, color: '#FFFFFF' };
        pixels.push(pixel);
  
        const pixelButton = createPixelButton(pixel);
        canvas?.appendChild(pixelButton);
      }
    }
  }

  function createPixelButton(pixel: Pixel): HTMLButtonElement {
    const pixelButton = document.createElement('button');
    pixelButton.style.backgroundColor = pixel.color;
    pixelButton.dataset.x = pixel.x.toString();
    pixelButton.dataset.y = pixel.y.toString();
    pixelButton.disabled = true;
    pixelButton.addEventListener('click', () => {
      const currentColor = pixel.color;
      const newColor = currentColor === '#FFFFFF' ? '#FF0000' : '#FFFFFF';
      pixel.color = newColor;
      pixelButton.style.backgroundColor = newColor;
      checkPattern();
    });
    canvasButtons.push(pixelButton);
    return pixelButton;
  }

  function initializeGame(): void {
    startButton = document.getElementById('startGame') as HTMLButtonElement | null;
    if (startButton) {
      startButton.addEventListener('click', startGame);
    }
    enableStartButton();
    disableCanvasButtons();
    clearTargetPattern();
  }

  function startGame(): void {
    if (isGameRunning) return;
  
    isGameRunning = true;
    timeRemaining = 30;
    score = 0;
    pixels.forEach(pixel => pixel.color = '#FFFFFF');
    targetPattern = generateTargetPattern();
    displayTargetPattern();
    updateTimer();
    updateScore();
    disableStartButton();
    enableCanvasButtons();
  }

  function generateTargetPattern(): Pixel[] {
    const pattern: Pixel[] = [];
    const patternSize = Math.floor(Math.random() * 3) + 2;
  
    for (let i = 0; i < patternSize; i++) {
      const x = Math.floor(Math.random() * 8);
      const y = Math.floor(Math.random() * 8);
      const color = '#FF0000';
      pattern.push({ x, y, color });
    }
  
    return pattern;
  }

  function displayTargetPattern(): void {
    const targetPatternElement = document.getElementById('targetPattern');
    if (targetPatternElement) {
      targetPatternElement.innerHTML = '';
      for (let y = 0; y < 8; y++) {
        for (let x = 0; x < 8; x++) {
          const cell = document.createElement('div');
          const targetPixel = targetPattern.find(pixel => pixel.x === x && pixel.y === y);
          if (targetPixel) {
            cell.style.backgroundColor = targetPixel.color;
          }
          targetPatternElement.appendChild(cell);
        }
      }
    }
  }

  function checkPattern(): void {
    const isMatch = targetPattern.every(targetPixel => {
      const playerPixel = pixels.find(pixel =>
        pixel.x === targetPixel.x && pixel.y === targetPixel.y
      );
      return playerPixel?.color === targetPixel.color;
    });
  
    if (isMatch) {
      score++;
      targetPattern = generateTargetPattern();
      displayTargetPattern();
      updateScore();
      resetGrid(); // Reset the grid after a correct guess
    }
  }

  function resetGrid(): void {
    pixels.forEach(pixel => pixel.color = '#FFFFFF');
    updateCanvas();
  }
  
  function updateCanvas(): void {
    pixels.forEach(pixel => {
      const pixelButton = document.querySelector(`#canvas button[data-x="${pixel.x}"][data-y="${pixel.y}"]`) as HTMLButtonElement;
      if (pixelButton) {
        pixelButton.style.backgroundColor = pixel.color;
      }
    });
  }

  function updateTimer(): void {
    const timerElement = document.getElementById('timeRemaining');
    if (timerElement) {
      timerElement.textContent = timeRemaining.toString();
    }
  
    if (timeRemaining > 0) {
      timeRemaining--;
      setTimeout(updateTimer, 1000);
    } else {
      endGame();
      isGameRunning = false;
      enableStartButton();
    }
  }

  function updateScore(): void {
    const scoreElement = document.getElementById('currentScore');
    if (scoreElement) {
      scoreElement.textContent = score.toString();
    }
  }

  function clearTargetPattern(): void {
    const targetPatternElement = document.getElementById('targetPattern');
    if (targetPatternElement) {
      targetPatternElement.innerHTML = '';
    }
  }

  function resetGame(): void {
    resetGrid();
    targetPattern = [];
    score = 0;
    timeRemaining = 30;
    updateScore();
    clearTargetPattern();
    enableStartButton();
    disableCanvasButtons();
  }

  function endGame(): void {
    const playAgain = confirm(`Game Over! Your score: ${score}\nDo you want to play again?`);
    if (playAgain) {
      resetGame();
    } else {
      isGameRunning = false;
      enableStartButton();
      disableCanvasButtons();
      clearTargetPattern();
    }
  }

  function disableStartButton(): void {
    startButton = document.getElementById('startGame') as HTMLButtonElement | null;
    if (startButton) {
      startButton.disabled = true;
    }
  }
  
  function enableStartButton(): void {
    if (startButton) {
      startButton.disabled = false;
    }
  }

  function disableCanvasButtons(): void {
    canvasButtons.forEach(button => button.disabled = true);
  }
  
  function enableCanvasButtons(): void {
    canvasButtons.forEach(button => button.disabled = false);
  }

  createCanvas();
  initializeGame();

  startButton = document.getElementById('startGame') as HTMLButtonElement | null;
  if (startButton) {
    startButton.addEventListener('click', startGame);
  }
```

### Step 4: Build and run the game

1. Open a terminal or command prompt and navigate to the project directory.
    
2. Run the following command `npx tsc --noEmitOnError` to compile the TypeScript code:
    

```bash
npx tsc --noEmitOnError
```

* This command compiles the TypeScript code in the `src/index.ts` file and generates the corresponding JavaScript code in the `src/index.js` file. We use the `--noEmitOnError` flag to stop it generating a `index.js` file if there are any errors.
    

After compiling the TypeScript code, you can open the `index.html` file in a web browser to play the game. The game will load, and you will see the pixel grid.

* Click the Start Game button to begin playing. This will show you the target grid with the pattern you need to match.
    
* Try to match the target pattern by clicking on the pixels to color them.
    
* The game will end when the time runs out or when you have matched all the patterns.
    
* Your final score will be displayed, and you will have the option to play again.
    

## The Challenge Continues

Congratulations! You've created a functional Pixel Match Game using TypeScript. But the challenge doesn't end here. Here are some ways you can extend the game:

1\. Add difficulty levels that change the grid size or time limit

2\. Implement a high score system using local storage

3\. Add sound effects for successful matches and game over

## Wrapping Up!

Congratulations, brave coder! You've conquered the second boss by creating a fully functional Pixel Match Game. Let's reflect on what you've accomplished:

1\. You've used TypeScript's type system to create a Pixel type, ensuring type safety throughout your code.

* You've implemented complex game logic using functions, demonstrating your mastery of TypeScript's function syntax.
    
* You've interacted with the DOM using TypeScript, showing how TypeScript can enhance web development.
    

Remember, each challenge you overcome makes you stronger. Keep practicing, keep coding, and get ready for the next level of your TypeScript adventure!

Happy Coding!
