Find Your Hat Challenge Project (JavaScript)

Here’s a clue to your Room For Improvement number 2: -

process.stdout.write("\u001b[2J\u001b[0;0H");

Love the ASCII art!

1 Like

It looked a bit scary at first but after I read some of the comments here and slept on it: -
My Find-Your-Hat Challenge.

This project started very very intimidating for me, but it came together and I got a lot of momentum in the home stretch!

Realizing how to track the player character with x and y coordinates as they relate to the height and width of the field was a breakthrough. Further, I’m proud of my method of having a base game field and a display field for the player that updates appropriately.

I took a lot of inspiration from past comments in this thread and amalgamized a lot of ideas and coded something for myself. Please hit me with some feedback! Thanks all

I don’t think this is the most elegant solution, but it works, it took a few days to get my head around it all. Happy with the outcome though :slight_smile:

Hi everyone. Just wanted to share my version of the project. I will probably work a little bit more on it later to finish the 7th task. If you have any feedback will be very grateful!
Happy coding!

Wow, this one feels hard lol. Does anyone want to jump on a zoom call and try to bounce some idea off each other?

OK, took most of the day to get my head around it, and I took some inspiration from some of the other attempts that folks have posted.

Here is my effort: Codecademy export · GitHub

Thanks,
Kiernan

Hi, I think you solution is really good. I really likes having a separate game field and a display field. Well done. :slight_smile:

Hi all. Here is my attempt. I prompted for the grid as many others did. I also forced the hat somewhere into the bottom right quadrant to maximize distance from a top left start. This does make the hat easier to find but guarantees a longer trajectory to the finish.

Github repository: FindYourHat/main.js at main · paulmarkster/FindYourHat · GitHub

Hi Kiernan, we seem to continue to be at the same point in the path… :slight_smile: I just published my hat project as well. I like how you added more protection around the prompts (i.e. upper/lower case). I see you also found a way to practice error injection. Well done!

(Let me know on Discord DM if you still want to get together on the Personal Portfolio project. It’s true that I have turned it into somewhat of a mega project. I completely understand if you are not interested. I have continued, with the latest changes now in GitHub.)

Hi Paul,

I like your solution. I noticed that you put all of the prompts for your generate field method actually in the the method, rather than randomly at the bottom of the code like I did. As soon as I saw that I immediately wanted to go in and change mine to do the same lol.

I also noticed that you use switch statement rather then if statements for the movement of the player in your getNewPosition method, I think a few other people did that as well. I have a tendency to lean a lot on if statements.

To be honest, I skipped ahead a bit in the full stack course yesterday to have a look at the start of the back end modules. I essentially wanted to take a break from the React part 2 modules because I was struggling a bit on the hooks lessons and thought some time looking at something else and coming back might help.

Ill drop you a message on discord regarding working together on something. :slight_smile:

Thanks,
Kiernan

Yes, I suspect we may all drift towards IF and FOR statements - I certainly do. I try to catch myself on the latter when working with arrays. I did a search on initializing two dimensional arrays and came up with iterative methods to do the same as FOR statements. I didn’t initially understand the need for the .FILL method, but now I think I do. I looked at the Codecademy solution after I finished the project and it seems they did it this way as well, although with slightly different syntax. I suppose it is a pretty common code pattern.

This was my solution , I was a challenge project, I feel proud to have achive the goal succesfully. I feel this project is a big door to more complex projects with more deteails in the use of interfaces, colaboration with professionals aposionated for coding

Here is my version of the Find The Hat. In this version you can select the starting point and create a random maze.
Find The Hat om my Github

Following is my code, I try to make it simple, thank you!

const prompt = require("prompt-sync")({ sigint: true });

//Field class
class Field {
  //constructor
  constructor(height, width) {
    this.height = height;
    this.width = width;
    this.playerPosition = { x: 0, y: 0 };
    this.message = "";
    this.isGameOver = false;
    this.field = this.generateField(height, width);
  }
  //generateField
  generateField(height, width) {
    let field = new Array(height)
      .fill(null)
      .map(() => new Array(width).fill("░"));

     //create starting point
    field[this.playerPosition.y][this.playerPosition.x] = "*";

     //create hat
    let hatplaced = false;
    while (!hatplaced) {
      let hatPosition = {
        x: Math.floor(Math.random() * width),
        y: Math.floor(Math.random() * height),
      };
      if (hatPosition.y != 0 || hatPosition.x != 0) {
        field[hatPosition.y][hatPosition.x] = "^";
        hatplaced = true;
      }
    }

     //create holes
    for (let i = 0; i < (width * height) / 5; i++) {
      let holeplaced = false;
      while (!holeplaced) {
        let holePosition = {
          x: Math.floor(Math.random() * width),
          y: Math.floor(Math.random() * height),
        };

        if (
          (holePosition.x != 0 || holePosition.y != 0) &&
          field[holePosition.y][holePosition.x] != "^"
        ) {
          field[holePosition.y][holePosition.x] = "O";
          holeplaced = true;
        }
      }
    }

    return field;
  }

  //print out field
  print() {
    process.stdout.write("\x1B[2J\x1B[0f");
    console.log(this.message);
    for (let row of this.field) {
      console.log(row.join(" "));
    }
    console.log("...............");
  }

 //move the star
  move(direction) {
    let oldY = this.playerPosition.y;
    let oldX = this.playerPosition.x;
    switch (direction) {
      case "d":
        if (oldY < this.height - 1) {
          this.playerPosition.y += 1;
          this.message = "";
        } else {
          this.message = "cant move";
        }
        break;
      case "u":
        if (oldY > 0) {
          this.playerPosition.y -= 1;
          this.message = "";
        } else {
          this.message = "cant move,try again";
        }
        break;
      case "r":
        if (oldX < this.width - 1) {
          this.playerPosition.x += 1;
          this.message = "";
        } else {
          this.message = "cant move,try again";
        }
        break;
      case "l":
        if (oldX > 0) {
          this.playerPosition.x -= 1;
          this.message = "";
        } else {
          this.message = "cant move,try again";
        }
        break;
    }
    let newY = this.playerPosition.y;
    let newX = this.playerPosition.x;
    this.field[oldY][oldX] = "░";
    if (this.field[newY][newX] === "O") {
      this.message = "You die!";
      this.field[newY][newX] = "X";
      this.isGameOver = true;
    } else if (this.field[newY][newX] === "^") {
      this.message = "You win!";
      this.field[newY][newX] = "W";
      this.isGameOver = true;
    } else {
      this.field[newY][newX] = "*";
    }
  }
}
//create a field using Field Class
const myField = new Field(6, 7);

//the game
function theGame(field) {
  while (!field.isGameOver) {
    field.print();

    const direction = prompt("Which way?");
    field.move(direction);
  }
  if (field.isGameOver) {
    field.print();
    console.log('Game is over!');
  }
}

theGame(myField);

image

image

I tried to have limited features in mine, and have it as straightforward as possible a solution.

If you have ideas on a more elegant solution I would love feedback!

const readline = require(“readline”);
const prompt = require(“prompt-sync”)({ sigint: true });

class Field {
constructor() {
this._field = [];
this._x = 0;
this._y = 0;
}
print() {
for (let i = 0; i < this._field.length; i++) {
for (let j = 0; j < this._field[i].length; j++) {
process.stdout.write(this._field[i][j] + " "); // Using process.stdout.write to print without newline
}
console.log();
}
}
startgame() {
//request input:
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
this.startturn(rl);
}
startturn(rl) {
rl.question(
"What direction do you want to go? (Use WASD): ",
(direction) => {
this.endturn(direction, rl);
}
);
}
endturn(direction, rl) {
//set new coordinates based on input
const error = “You can’t go that way! Game Over.”;
switch (direction) {
case “a”: //left
if (this._x - 1 < 0) {console.log(error) return;} else {this._x–;}
break;
case “d”: //right
if (this._x + 1 > this._field[0].length) {console.log(error) return;} else {this._x++;}
break;
case “s”: //down
if (this._y + 1 > this._field.length) {console.log(error) return;} else {this._y++;}
break;
case “w”: //up
if (this._y - 1 < 0) {console.log(error) return;} else {this._y–;}
break;
}
//is it a hole, hat or create path?
let landing = this._field[this._y][this._x];
if (landing === “^”) {
console.log(“You win!”);
return;
} else if (landing === “O”) {
console.log(“You fell in a hole! Game over!”);
return;
} else {
this._field[this._y][this._x] = “*”;
this.print();
this.startturn(rl);
}
}
generateField() {
// I refactored this into a function I could call so there wasn’t so many lines
const randsize = (mult) => Math.floor((Math.random() + 1) * mult);

//subtract and add 1 to make sure we dont land on 0,0
const randposition = (coord) => Math.floor(Math.random() * ( coord - 1 )) + 1

//set blank portrait shaped field
const x = randsize(5)
const y = randsize(10)
this._field = new Array(y).fill().map(() => new Array(x).fill('░'));

//add criteria
this._field[0][0] = '*'
const xhat = randposition(x)
const yhat = randposition(y)
this._field[yhat][xhat] = '^'

//add holes
let spaces = (x * y) - 2 
let holes = Math.floor(spaces * 0.10)

for(let i=0; i < holes; i++){
  let xhole = randposition(x)
  let yhole = randposition(y)
  if(xhole !== xhat && yhole !== yhat)(
    this._field[yhole][xhole] = 'O')}

}
}

const myField = new Field();
myField.generateField();
myField.print()
myField.startgame();

Here is my version!
I wanted to be a bit kinder and just kindly let people know they were at the edge of the field rather than letting them fall off the edge and lose the game!

Here is my code :slight_smile:

This was a fun one!

Hello everyone. I published my solution as well. I feel like it was pretty difficult for me, I just tried to use chat GPT at first to help me, but I still had some issues. I checked my version with solution code and tried to understand the logic… I hope to just remember all that I had written :smiling_face_with_tear:

Find-Your-Hat

2 Likes

My completed code for the challenge! Big thanks to @kayleung11, whose code allowed me to understand the structure of this challenge, before writing my own.

If anybody reads this, a question. The challenge says to place the .generateField() method within the Field class. I built mine outside, not fully realizing that, but the game functions just fine. Is there a reason why it would be better to have it inside the class, rather than as a separate function?

Cheers!