Need help with Challenge Project: Find Your Hat help forum

Hi,

I am having issues with Challenge Project: Find Your Hat .
I get the error "this.checkWin is not a function " and I don’t understand how to remedy it . I tried google but got stuck , so I am hoping that someone here might help me .
here is the code

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

const hat = '^';
const hole = 'O';
const fieldCharacter = '░';
const pathCharacter = '*';

const arr = [
[pathCharacter, fieldCharacter, hole],
[fieldCharacter, hole, fieldCharacter],
[fieldCharacter, hat, fieldCharacter]
]

class Field {
    constructor(field) {
     this.field = field.map(line => line.join('')).join('\n');     
    }     
    print() {
      process.stdout.write(this.field);
    }    
    
    position (x) {
     return this.field.charAt(x);
    }

    checkWin (x) {
        let here = this.position(x);
        if (here == hat) {
          process.stdout.write(`\n Congrats! You found your hat ! \n`);
          process.exit();
        }
        else if (here == hole) {
          process.stdout.write(`\n You fell into a whole\n`);
          process.exit();
        }
        else if (here !== fieldCharacter) {
          process.stdout.write(`\n You are out of bounds \n`);
          process.exit();
        }
        else {
          this.field.replace(this.position(x), pathCharacter )
          this.play();
        }
      
    }

    handleInput (userInput) {
        const char = userInput.toString().trim();
            let initial = 0;
            if (char === 'U' || char === 'u') {
              this.checkWin(initial - 4);
            }
            else if (char === 'D' || char === 'd') {
             this.checkWin(initial + 4);
            }
            else if (char === 'R' || char === 'r') {
              this.checkWin(initial + 1);
            }
            else if (char === 'L' || char === 'l') {
              this.checkWin(initial -1 );
            }
            else {
              process.stdout.write('U is up, D is down, R is right, L is left \n');
            }
    }

    play() {
      this.print();
      process.stdout.write('\n Which way?  ')
      process.stdin.on('data', this.handleInput)
    }
  }
 
 const gameFiled = new Field(arr);
 
 gameFiled.play();

In the play function,
I’d change
process.stdin.on('data', this.handleInput)
to
process.stdin.on('data', (e) => this.handleInput(e));
otherwise, the this in the handleInput becomes a ReadStream object.

Also,
in the checkWin object,
you have
this.field.replace(this.position(x), pathCharacter )
but this does not change the this.field string, it returns a new string
so you may want
this.field = this.field.replace(this.position(x), pathCharacter )

I recommend having the user’s position as a property of the object so that multiple methods can use it and change it.

thank you very much, your info was very helpful and took me to the next level .

I am confused about how to use user’s position as a property . I have tried to move it in the constructor as this.position = new Function (x => this.field.charAt(x)) but it didn’t work.

For a reason I am struggling to understand , the pathCharacter is not replaced in the right position. there is something broken in the connection.

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

const hat = '^';
const hole = 'O';
const fieldCharacter = '░';
const pathCharacter = '*';

const arr = [
[pathCharacter, fieldCharacter, hole],
[fieldCharacter, hole, fieldCharacter],
[fieldCharacter, hat, fieldCharacter]
]

class Field {
    constructor(field, x = 0) {
     this.field = field.map(line => line.join('')).join('\n');     
    } 

    print() {
      process.stdout.write(this.field);
    }    
    
    position (x) {
     return this.field.charAt(x);
    }

    checkWin (x) {
        let here = this.position(x);
        if (here == hat) {
          process.stdout.write(`\n Congrats! You found your hat ! \n`);
          process.exit();
        }
        else if (here == hole) {
          process.stdout.write(`\n You fell into a whole\n`);
          process.exit();
        }
        else if (here !== fieldCharacter) {
          process.stdout.write(`\n You are out of bounds \n`);
          process.exit();
        }
        else {
          this.field = this.field.replace(this.position(x), pathCharacter );         
          this.play();
        }
      
    }

    handleInput (userInput) {
      const char = userInput.toString().trim();        
      let here = this.field.lastIndexOf(pathCharacter);            
      if (char === 'U' || char === 'u') {
        this.checkWin(here - 4);
      }
      else if (char === 'D' || char === 'd') {
       this.checkWin(here + 4);
      }
      else if (char === 'R' || char === 'r') {
        this.checkWin(here + 1);
      }
      else if (char === 'L' || char === 'l') {
        this.checkWin(here - 1 );
      } 
      else {
        process.stdout.write('U is up, D is down, R is right, L is left \n');
      }
    }

    play() {
      this.print();
      process.stdout.write('\n Which way?  ')
      process.stdin.on('data', e => this.handleInput(e))
    }
  }
 
 const gameFiled = new Field(arr);
 
 gameFiled.play();

You could have that position as a number:
Here’s a version using userPosition as a property (that holds a number, not a function):

class Field {
    constructor(field, x = 0) {
     this.field = field.map(line => line.join('')).join('\n');    
     this.userPosition = x;
    } 

and correspondingly, in the handleInput method, instead of using here as a variable,
you could do something like:

      if (char === 'U' || char === 'u') {
        this.userPosition = this.userPosition - 4;
        this.checkWin(this.userPosition);
      }

If the this.field.replace does not work correctly, you could make your own method so that you could do this.replaceAt instead:

   replaceAt(position, newCharacter) {
     const str = this.field;
     return str.subString(0, position) + newCharacter + str.substring(position + 1);
   }

Here’s a reference for the .substring for strings: MDN substring method

Note that

let here = this.field.lastIndexOf(pathCharacter); 

may not get the user’s position because this gets the position of the first * in the string, which may or may not be the user’s position.

Thanks for that !

I can now narrow it down to two separate issues :

  1. I created a replaceAt method , but it doesn’t work and I don’t understand why . I have checked the index (userPosition) update and it seems to work fine.

  2. The second userInput I use in the console automatically doubles the move ; this doesn’t seem to be an automatic double play() call because neither the new field nor the “Wich way” output are printed. It is only doing double computing of the userPosition.
    image

see updated code here :

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

const hat = '^';
const hole = 'O';
const fieldCharacter = '░';
const pathCharacter = '*';

const arr = [
[pathCharacter, fieldCharacter, hole],
[fieldCharacter, fieldCharacter, hole],
[fieldCharacter, hat, fieldCharacter]
]

class Field {
    constructor(field, x = 0) {
     this.field = field.map(line => line.join('')).join('\n'); 
     this.userPosition = x;    
    } 

    print() {
      process.stdout.write(this.field);
    }    
    
    replaceAt(position, newCharacter) {
      const str = this.field;
      return str.substring(0, position) + newCharacter + str.substring(position + 1);
    }

    checkWin (userPosition) {   
        let symbol = this.field[userPosition] ;    
        if (symbol == hat) { 
          process.stdout.write(`\n Congrats! You found your hat ! \n`);          
          process.exit();
        }
        else if (symbol == hole) {          
          process.stdout.write(`\n You fell into a whole\n`);            
          process.exit();
        }
        else if (symbol !== fieldCharacter) {           
          process.stdout.write(`\n You are out of bounds \n`);          
          process.exit();
        }
        else {
          this.replaceAt(userPosition, pathCharacter)                 
          this.play();
        }
      
    }

    handleInput (userInput) {
      const char = userInput.toString().trim();                  
      if (char === 'U' || char === 'u') {
        this.userPosition = this.userPosition - 4;        
        this.checkWin(this.userPosition);
      }
      else if (char === 'D' || char === 'd') {
        this.userPosition = this.userPosition + 4;
        process.stdout.write('\n' + this.userPosition + '\n');
        this.checkWin(this.userPosition);
      }
      else if (char === 'R' || char === 'r') {
        this.userPosition = this.userPosition + 1;
        process.stdout.write('\n' + this.userPosition + '\n'); 
        this.checkWin(this.userPosition);
      }
      else if (char === 'L' || char === 'l') {
        this.userPosition = this.userPosition - 1;
        this.checkWin(this.userPosition);
      } 
      else {
        process.stdout.write('U is up, D is down, R is right, L is left \n');
      }
    }

    play() {
      this.print();
      process.stdout.write('\n Which way?  ')
      process.stdin.on('data', e => this.handleInput(e))
    }
  }
 
 const gameFiled = new Field(arr);
 
 gameFiled.play();

Update: I have solved both problems . Thank you very much for your help , I really appreciate it!

here is the final code :

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

const hat = '^';
const hole = 'O';
const fieldCharacter = '░';
const pathCharacter = '*';

const arr = [
[pathCharacter, fieldCharacter, hole],
[fieldCharacter, fieldCharacter, hole],
[fieldCharacter, hat, fieldCharacter]
]

class Field {
    constructor(field, x = 0) {
     this.rowLength = field[0].length + 1;
     this.field = field.map(line => line.join('')).join('\n');
     this.userPosition = x;      
    } 

    static generateField(x, y) {
      let arr = [];
      let options = [ fieldCharacter, hole, fieldCharacter]; 
      let randomHatIndexX = Math.ceil(Math.random() * x-1)  
      let randomHatIndexY = Math.ceil(Math.random() * y-1)    
      for(let i = 0; i < y; i++) {  
        let yArr = [];       
        for(let j = 0; j < x; j++) {
         let randomIndex = Math.floor(Math.random() * 3);
          yArr.push(options[randomIndex]);          
        }     
        arr.push(yArr);     
       }  
       arr[0][0] = pathCharacter; 
       arr[randomHatIndexY][randomHatIndexX] = hat;    
       return arr;     
   }

    replaceAt(position, newCharacter) {
      this.field = this.field.substring(0, position) + newCharacter + this.field.substring(position + 1); 
    }

    print() {
      process.stdout.write(this.field);
    } 

    checkWin (userPosition) {   
        let symbol = this.field[userPosition] ;    
        if (symbol == hat) { 
          process.stdout.write(`\n Congrats! You found your hat ! \n`);          
          process.exit();
        }
        else if (symbol == hole) {          
          process.stdout.write(`\n You fell into a whole\n`);            
          process.exit();
        }
        else if (symbol !== fieldCharacter) {           
          process.stdout.write(`\n You are out of bounds \n`);          
          process.exit();
        }
        else {
          this.replaceAt(this.userPosition, pathCharacter) 
          this.print();
          process.stdout.write('\n Which way?  ') 
          console.log(this.rowLength);                          
        }     
    }

    handleInput (userInput) {
      const char = userInput.toString().trim();                  
      if (char === 'U' || char === 'u') {
        this.userPosition = this.userPosition - this.rowLength;        
        this.checkWin(this.userPosition);
      }
      else if (char === 'D' || char === 'd') {
        this.userPosition = this.userPosition + this.rowLength;
        console.log(this.userPosition)
        this.checkWin(this.userPosition);
      }
      else if (char === 'R' || char === 'r') {
        this.userPosition = this.userPosition + 1;
        console.log(this.userPosition) 
        this.checkWin(this.userPosition);
      }
      else if (char === 'L' || char === 'l') {
        this.userPosition = this.userPosition - 1;
        this.checkWin(this.userPosition);
      } 
      else {
        process.stdout.write('U is up, D is down, R is right, L is left \n');
      }
    }

    play() {
      this.print();
      process.stdout.write('\n Which way?  ')
      process.stdin.on('data', e => this.handleInput(e))
    }
  }
 
 let arr2 =  Field.generateField(3, 4);

 const gameFiled = new Field(arr2);

 gameFiled.play();