ga-wdi-boston / game-project

Other
7 stars 102 forks source link

store the state of my game #837

Closed ryanwk closed 7 years ago

ryanwk commented 7 years ago

I need help getting started with storing the state of my game, general planning, etc. I'm not sure how to approach this.

I think what I need is a patch request?

my goal is to: keep the server informed of anything that happens with the game (when an x or o is placed on the board, who's turn it is, games played, etc.)

in order to fulfill this MVP requirement: Communicate with a back-end to store the state of your game.

I've been trying to simulate Ingrid's code:

const updateGame = function (data) {
  console.log('data is', data)
  return $.ajax({
    url: app.host + '/games/' + store.game.id,
    method: 'PATCH',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
}

I've read through these relevant issues and documentation: https://git.generalassemb.ly/ga-wdi-boston/game-project-api https://github.com/ga-wdi-boston/game-project/issues/825 https://github.com/ga-wdi-boston/game-project/issues/800

benjimelito commented 7 years ago

Are you currently getting an error when trying to run this updateGame function? Or is the issue that you aren't sure how to trigger this request?

Jcornmanhomonoff commented 7 years ago

Look at the game project api for what data the api is expecting for an update or PATCH. That would be a good place to start.

benjimelito commented 7 years ago

So based on what we talked about:

  1. In your toggleTurn function, you need to have access to 3 variables in order to make the PATH request: The letter that was placed, the index of the cell that was clicked, and whether the game is over or not.

  2. Once you have these variables, you can build up a data object with them.

  3. You can then call api.updateGame with the data object you have created.

jordanallain commented 7 years ago

Any progress @ryanwk ?

ryanwk commented 7 years ago

Yes, I did what ben said. My console logs dont confirm that data is being updated. How can I confirm that the patch request is working?

jordanallain commented 7 years ago

if you open up the dev tools in chrome, there is a Network tab that you can click. you should then see a stack of the requests that you've made to the API. I believe the bottom one is the latest one, so if you click that it should show you some more information about the request like this.

Request URL:https://github.com/settings/replies?context=issue
Request Method:GET
Status Code:200 OK
Remote Address:192.30.255.113:443
Referrer Policy:no-referrer-when-downgrade

If it says PATCH and 200 OK then hooray!

ryanwk commented 7 years ago

The console logs are not displaying for the functions that create and update a game and handle the subsequent post / patch requests.

When I check the network tab I get 200's except for the most recent on called 'websocket'.

network tab:

?credentials%5Bemail%5D=&credentials%5Bpassword%5D= vendor.js application.js info?t=1498776429463 websocket

what 'websocket' says:

Request URL:ws://localhost:7165/sockjs-node/720/fpvdghfu/websocket Request Method:GET Status Code:101 Switching Protocols


api.js file

const updateGame = function (data) {
  console.log('update game is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/' + store.game.id,
    method: 'PATCH',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
}
const createGame = function (data) {
  console.log('creategame is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/',
    method: 'POST',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
}

events.js file:

const onUpdateGame = function (letter, index, gameOver) {
  console.log('onUpdateGame is being invoked')
  const data = {
    'game': {
      'cell': {
        'index': index,
        'value': letter
      },
      'over': gameOver
    }
  }
  api.updateGame(data)
    .then(ui.updateGameSuccess)
    .catch(ui.failure)
}

ui.js file:

const updateGameSuccess = () => {
  // handle success
  console.log('game has been updated with index, letter placed, and game status')
}
const failure = () => {
  // handle failure
  console.log('the request did not work!')
}
ryanwk commented 7 years ago

my console logs do work for this function but don't work for the update / create game functions.


events.js file:

// invoked with a click on a cell of the gameboard, places a symbol in the corresponding cell, updates the gameState array with a new value, update boolean to switch players turn
const toggleTurn = function (event) {
  index = $(event.target).attr('id')
  console.log('this is index: ' + index)
  if (gameState[this.id] === 0) {
    if (xTurn) {
      $(this).text('X')
      xTurn = false
      gameState[this.id] = 1
      if (checkForWin(1)) {
        alert('X wins!')
        gameOver = true
        console.log('this is gameOver: ' + gameOver)
      }
    } else {
      $(this).text('O')
      xTurn = true
      index = $(event.target.id)
      gameState[this.id] = 2
      if (checkForWin(2)) {
        alert('O wins!')
        gameOver = true
        console.log('this is gameOver: ' + gameOver)
      }
    }
    letter = $(this).text()
    console.log('this is letter: ' + letter)
  }
  if (turnCounter++ === 8) {
    alert('draw!')
    gameOver = true
  }
  console.log(turnCounter)
  console.log('this is gameOver: ' + gameOver)
  // onUpdateGame(letter, index, gameOver)
}
ryanwk commented 7 years ago

Oh man.. I think I know what it is. toggleTurn had the function that invokes onUpdateGame commented out. Let's see if this works...

ryanwk commented 7 years ago

Ok good news, they are being invoked.... but now a new issue..

error message:

onUpdateGame is being invoked update game is being invoked 19:08:35.129 api.js:52 Uncaught TypeError: Cannot read property 'id' of undefined at Object.updateGame (api.js:52) at onUpdateGame (events.js:97) at HTMLDivElement.toggleTurn (events.js:63) at HTMLDivElement.dispatch (jquery.js:5206) at HTMLDivElement.elemData.handle (jquery.js:5014)


error source:

const updateGame = function (data) {
  console.log('update game is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/' + store.game.id,
    method: 'PATCH',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
}
ryanwk commented 7 years ago

and there's more.. when I try to sign out:

api.js:40 Uncaught TypeError: Cannot read property 'id' of undefined at Object.signOut (api.js:40) at HTMLDivElement. (index.js:38) at HTMLDivElement.dispatch (jquery.js:5206) at HTMLDivElement.elemData.handle (jquery.js:5014)

  line 40:     url: config.apiOrigin + '/sign-out/' + store.user.id,
jordanallain commented 7 years ago

is this the local or deployed app?

ryanwk commented 7 years ago

local? how can I tell?

jordanallain commented 7 years ago

in the browser are you at localhost or github.io

ryanwk commented 7 years ago

localhost

jordanallain commented 7 years ago

alright are you still able to sign up and sign in?

ryanwk commented 7 years ago

So I just signed in, signed up, started a game, and started playing a game. 'I removed .id from lines 40 and 52' to see if that might be the issue.

This is what I've got:

network: Request URL:https://aqueous-atoll-85096.herokuapp.com/games/undefined Request Method:PATCH Status Code:404 Not Found Remote Address:54.225.138.206:443 Referrer Policy:no-referrer-when-downgrade


events.js: 

const onUpdateGame = function (letter, index, gameOver) {
  console.log('onUpdateGame is being invoked')
  const data = {
    'game': {
      'cell': {
        'index': index,
        'value': letter
      },
      'over': gameOver
    }
  }
  api.updateGame(data)
    .then(ui.updateGameSuccess)
    .catch(ui.failure)
}

api.js:

const updateGame = function (data) {
  console.log('update game is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/' + store.game,
    method: 'PATCH',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
}
ryanwk commented 7 years ago

console:

19:14:22.943 api.js:18 Object {credentials: Object} 19:14:23.241 ui.js:9 user has signed up [object Object] 19:14:34.929 api.js:28 Object {credentials: Object} 19:14:35.081 ui.js:13 user has signed in: [object Object] 19:14:40.919 api.js:61 creategame is being invoked 19:14:47.997 events.js:32 this is index: 0 19:14:47.998 events.js:55 this is letter: X 19:14:47.998 events.js:61 1 19:14:47.999 events.js:62 this is gameOver: false 19:14:47.999 events.js:87 onUpdateGame is being invoked 19:14:47.999 api.js:50 update game is being invoked 19:14:48.100 ui.js:27 the request did not work!

jordanallain commented 7 years ago

look at the URL for the PATCH request

https://aqueous-atoll-85096.herokuapp.com/games/undefined

can you post your function for handling the successful creation of a new game?

ryanwk commented 7 years ago

I don't have a success function in my ui.js for creating a new game. but heres the createGame function in my api.js file:

const createGame = function (data) {
  console.log('creategame is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/',
    method: 'POST',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
}

not sure if it's relevant but here's the success function for when a user signs in:

const signInSuccess = (data) => {
  // handle success
  console.log('user has signed in: ' + data)
  store.user = data.user
}
jordanallain commented 7 years ago

so notice how in signInSuccess we get a data object back that has a user object inside it. We save that user object inside of our store so we can use its id, among other things.

if you're not already, you should be doing something similar with the data object that gets returned to us from successfully creating a new game. does this help?

ryanwk commented 7 years ago

Yes, makes sense. I just created this variable

would I want something like 'store.game = data.game' ?

const createGameSuccess = (data) => {
  // handle success
  console.log('user has signed in: ' + data)
  store.game = data.game
}

and then the createGame function would have something like this?

const createGame = function (data) {
  console.log('creategame is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/' + store.game,
    method: 'POST',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
}
ryanwk commented 7 years ago

ok, so signed-up, signed-in, started game but it breaks when the createGame function is invoked.

ryanwk commented 7 years ago

const createGame = function (data) {
  console.log('creategame is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/' + store.game,
    method: 'POST',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
  .done(ui.createGameSuccess)
  .fail(ui.failure)
}

const createGameSuccess = (data) => {
  // handle success
  console.log('user has signed in: ' + data)
  store.game = data.game
}
const failure = () => {
  // handle failure
  console.log('the request did not work!')
}
jordanallain commented 7 years ago

heres the API docs for how you should build a POST request to create a game:

POST /games

what URL are you trying to hit in your createGame function?

jordanallain commented 7 years ago

url: config.apiOrigin + '/games/' + store.game,

looks like you're adding something to the end you don't need

jordanallain commented 7 years ago

remember the game doesn't have an id associated with it until it is created on the back end

ryanwk commented 7 years ago

I sat down with Jess earlier and this was the only way it would work, if I set up config like so:

const config = { apiOrigins: { development: 'https://aqueous-atoll-85096.herokuapp.com', production: 'https://aqueous-atoll-85096.herokuapp.com' } } module.exports = config

Ok, makes sense, I'll try removing 'store.game'.

ryanwk commented 7 years ago

ok, that worked, now I can create a game but it breaks when we get to updateGame:

const updateGame = function (data) {
  console.log('update game is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/' + store.game,
    method: 'PATCH',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
}
const createGame = function (data) {
  console.log('creategame is being invoked')
  return $.ajax({
    url: config.apiOrigin + '/games/',
    method: 'POST',
    headers: {
      Authorization: 'Token token=' + store.user.token
    },
    data
  })
  .done(ui.createGameSuccess)
  .fail(ui.failure)
}

ui.js :

const signInSuccess = (data) => {
  // handle success
  console.log('user has signed in: ' + data)
  store.user = data.user
}
const signOutSuccess = () => {
  // handle success
  console.log('user has signed out')
  store.user = {}
}
const updateGameSuccess = () => {
  // handle success
  console.log('game has been updated with index, letter placed, and game status')
}
const createGameSuccess = (data) => {
  // handle success
  console.log('game has been created: ' + data)
  store.game = data.game
}
const failure = () => {
  // handle failure
  console.log('the request did not work!')
}

error message: api.js:28 Object {credentials: Object} 19:51:33.525 ui.js:13 user has signed in: [object Object] 19:51:36.610 api.js:61 creategame is being invoked 19:51:36.701 ui.js:27 game has been created: [object Object] 19:51:40.308 events.js:32 this is index: 0 19:51:40.310 events.js:55 this is letter: X 19:51:40.310 events.js:61 1 19:51:40.310 events.js:62 this is gameOver: false 19:51:40.311 events.js:87 onUpdateGame is being invoked 19:51:40.311 api.js:50 update game is being invoked 19:51:40.405 ui.js:32 the request did not work!

network tab:

Request URL:https://aqueous-atoll-85096.herokuapp.com/games/[object%20Object] Request Method:PATCH Status Code:404 Not Found Remote Address:23.23.196.129:443 Referrer Policy:no-referrer-when-downgrade

jordanallain commented 7 years ago

Almost There!!

This is the URL you are sending the PATCH to:

url: config.apiOrigin + '/games/' + store.game

Do you see what we might need to add to the end?

jordanallain commented 7 years ago

store.game is being turned into a string of [object Object]...so maybe that object has something inside of it that we want to utilize, like we did with store.user.?

jordanallain commented 7 years ago

as a reminder the API docs say that we should send a PATCH request to /games/:id

ryanwk commented 7 years ago

it worked!!!!! I added '.id' to the end of that PATCH URL.

console: api.js:50 updateGame is being invoked 20:03:14.355 ui.js:23 game has been updated with index, letter placed, and game status

network: Request URL:https://aqueous-atoll-85096.herokuapp.com/games/7262 Request Method:PATCH Status Code:200 OK Remote Address:23.23.171.171:443 Referrer Policy:no-referrer-when-downgrade

ryanwk commented 7 years ago

Thank you!!!!

ryanwk commented 7 years ago

no!!! it broke again!!

ryanwk commented 7 years ago

Object {credentials: Object} 20:03:09.632 ui.js:13 user has signed in: [object Object] 20:03:12.406 api.js:61 createGame is being invoked 20:03:12.519 ui.js:27 game has been created: [object Object] 20:03:14.246 events.js:32 this is index: 0 20:03:14.248 events.js:55 this is letter: X 20:03:14.248 events.js:61 1 20:03:14.249 events.js:62 this is gameOver: false 20:03:14.249 events.js:87 onUpdateGame is being invoked 20:03:14.250 api.js:50 updateGame is being invoked 20:03:14.355 ui.js:23 game has been updated with index, letter placed, and game status 20:06:54.423 events.js:32 this is index: 1 20:06:54.423 events.js:55 this is letter: O 20:06:54.424 events.js:61 2 20:06:54.424 events.js:62 this is gameOver: false 20:06:54.424 events.js:87 onUpdateGame is being invoked 20:06:54.425 api.js:50 updateGame is being invoked 20:06:59.782 jquery.js:8430 Uncaught TypeError: Illegal invocation at add (jquery.js:8430) at buildParams (jquery.js:8417) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at Function.jQuery.param (jquery.js:8450) at Function.ajax (jquery.js:9040) add @ jquery.js:8430 buildParams @ jquery.js:8417 buildParams @ jquery.js:8411 buildParams @ jquery.js:8411 buildParams @ jquery.js:8411 buildParams @ jquery.js:8411 buildParams @ jquery.js:8411 buildParams @ jquery.js:8411 jQuery.param @ jquery.js:8450 ajax @ jquery.js:9040 updateGame @ api.js:51 onUpdateGame @ events.js:97 toggleTurn @ events.js:63 dispatch @ jquery.js:5206 elemData.handle @ jquery.js:5014 20:07:09.409 events.js:32 this is index: 2 20:07:09.410 events.js:55 this is letter: X 20:07:09.410 events.js:61 3 20:07:09.410 events.js:62 this is gameOver: false 20:07:09.411 events.js:87 onUpdateGame is being invoked 20:07:09.411 api.js:50 updateGame is being invoked 20:07:09.705 ui.js:23 game has been updated with index, letter placed, and game status 20:07:12.171 events.js:32 this is index: 3 20:07:12.172 events.js:55 this is letter: O 20:07:12.172 events.js:61 4 20:07:12.173 events.js:62 this is gameOver: false 20:07:12.173 events.js:87 onUpdateGame is being invoked 20:07:12.173 api.js:50 updateGame is being invoked 20:08:19.988 jquery.js:8430 Uncaught TypeError: Illegal invocation at add (jquery.js:8430) at buildParams (jquery.js:8417) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at Function.jQuery.param (jquery.js:8450) at Function.ajax (jquery.js:9040)

ryanwk commented 7 years ago

@jordanallain X's work fine but when it's O's turn it breaks!

20:06:59.782 jquery.js:8430 Uncaught TypeError: Illegal invocation at add (jquery.js:8430)

jordanallain commented 7 years ago

drop a debugger in there, step through line by line so you can see at which line it is breaking

ryanwk commented 7 years ago

alright, debuggers in, refreshed the page ..everything works fine sign-in, start game, on X's turn it works, but when we switch to O's turn and upon clicking it breaks. This is what I get:

jquery.js:8430 Uncaught TypeError: Illegal invocation at add (jquery.js:8430) at buildParams (jquery.js:8417) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at buildParams (jquery.js:8411) at Function.jQuery.param (jquery.js:8450) at Function.ajax (jquery.js:9040)

in the sources tab: // If value is a function, invoke it and use its return value var value = jQuery.isFunction( valueOrFunction ) ? valueOrFunction() : valueOrFunction;

        s[ s.length ] = encodeURIComponent( key ) + "=" +
            encodeURIComponent( value == null ? "" : value );
    };
ryanwk commented 7 years ago

there's an error on line 8430 here valueOrFunction() :

jordanallain commented 7 years ago

can you post the function that runs every time you click? and if possible, the function that is deciding that its O's turn or placing the O.

ryanwk commented 7 years ago

let xTurn = true
let gameState = [0, 0, 0, 0, 0, 0, 0, 0, 0]
let turnCounter = 0

let index = ''
let letter = ''
let gameOver = false

// event listeners
const addHandlers = function () {
  $('.game-cell').on('click', toggleTurn)
  $('#resetButton').on('click', resetBoard)
}
// invoked with a click on a cell of the gameboard, places a symbol in the corresponding cell, updates the gameState array with a new value, update boolean to switch players turn
const toggleTurn = function (event) {
  index = $(event.target).attr('id')
  console.log('this is index: ' + index)
  if (gameState[this.id] === 0) {
    if (xTurn) {
      $(this).text('X')
      xTurn = false
      gameState[this.id] = 1
      if (checkForWin(1)) {
        alert('X wins!')
        gameOver = true
        console.log('this is gameOver: ' + gameOver)
      }
    } else {
      $(this).text('O')
      xTurn = true
      index = $(event.target.id)
      gameState[this.id] = 2
      if (checkForWin(2)) {
        alert('O wins!')
        gameOver = true
        console.log('this is gameOver: ' + gameOver)
      }
    }
    letter = $(this).text()
    console.log('this is letter: ' + letter)
  }
  if (turnCounter++ === 8) {
    alert('draw!')
    gameOver = true
  }
  console.log(turnCounter)
  console.log('this is gameOver: ' + gameOver)
  onUpdateGame(letter, index, gameOver)
  debugger
}
ryanwk commented 7 years ago

I was storing letter as this: letter = $(this).text() should have been this: letter = 'X'