[solved] Resetting a table back to it's original values

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
AlexCalv
Prole
Posts: 49
Joined: Fri Aug 08, 2014 7:12 pm
Contact:

[solved] Resetting a table back to it's original values

Post by AlexCalv »

I'm trying to 'restart' my game and the only way I can think of is calling the player table when you lose. I know I could turn the table into a function but if I do that, then I have to change all of my functions from "player.Draw()" to "playerDraw()" for example. If I don't then I get an error. Is there a way to I guess, recall a table with it's original set values?

This is my player table if you need it.

Code: Select all

player = {x = 10,
	y = 636,
	width = 80,
	height = 80,
	speed = 300,
	xVel = 0,
	yVel = 0,
	jumpVel = -800,
	score = 0,
	lives = 3,
	state = "stand"
}
Last edited by AlexCalv on Sun Oct 05, 2014 7:07 am, edited 1 time in total.
davisdude
Party member
Posts: 1154
Joined: Sun Apr 28, 2013 3:29 am
Location: North Carolina

Re: Resetting a table back to it's original values

Post by davisdude »

You could make another variable with the exact same values as the other table, and then at the end reset it. Note that this is not allowed:

Code: Select all

oldTable = table
This doesn't work because the values in oldTable will be changed each time the "table's" values are changed. Instead, do something like this:

Code: Select all

local function DeepCopy( Table, Cache ) -- Robin's code.
    if type( Table ) ~= 'table' then
        return Table
    end

    Cache = Cache or {}
    if Cache[Table] then
        return Cache[Table]
    end

    local New = {}
    Cache[Table] = New
    for Key, Value in pairs( Table ) do
        New[Globals.DeepCopy( Key, Cache)] = Globals.DeepCopy( Value, Cache )
    end

    return New
end
Then implement it:

Code: Select all

Table = { 1, 2, 3 }
OldTable = DeepCopy( Table )

-- Game stuff

if RestartGame then
    Table = OldTable
    -- All the other variables, in this style.
end
GitHub | MLib - Math and shape intersections library | Walt - Animation library | Brady - Camera library with parallax scrolling | Vim-love-docs - Help files and syntax coloring for Vim
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Resetting a table back to it's original values

Post by ivan »

There are several ways to solve this.
Davisdude's method is very good although I prefer a slightly different implementation:

Code: Select all

--- Copies the contents from one table to another
--- Does not remove existing elements in the destination table
-- @param s Source table
-- @param d Destination table (optional)
-- @return The destination table
function table.copy(s, d)
  assert(s, "table is nil")
  assert(s ~= d, "source and destination tables must be different")
  d = d or {}
  for k, v in pairs(s) do
    if type(v) == "table" then
      if d[k] == nil then
        d[k] = {}
      end
      table.copy(v, d[k])
    else
      d[k] = v
    end
  end
  return d
end
Slightly different from Davisdude's example, since it does not overwrite the "current" reference:

Code: Select all

default = { 1, 2, 3 }
current = {}

function restartgame()
  table.copy(default, current)
end
I have a generic "replace" function for tables that you might find useful:

Code: Select all

--- Replaces the existing values in a table
--- Optionally, converts the source values to match the destination types
-- @param s Source table
-- @param d Destination table
-- @param m Convert source values to destination types (optional)
-- @return The number of replaced values
local function toboolean(v)
  if v == 'true' then
    return true
  elseif v == 'false' then
    return false
  end
end
function table.replace(s, d, m)
  assert(s, "source table is nil")
  assert(d, "destination table is nil")
  assert(s ~= d, "source and destination tables must be different")
  local n = 0
  -- iterate destination table
  for k, dv in pairs(d) do
    local sv = s[k]
    local dt = type(dv)
    local st = type(sv)
    if st == "table" and dt == "table" then
      -- recursive
      n = n + table.replace(sv, dv, m)
    else
      -- convert source value to destination type
      if m == true and dt ~= st then
        if dt == 'boolean' then
          sv = toboolean(sv)
        elseif dt == 'number' then
          sv = tonumber(sv)
        elseif dt == 'string' then
          sv = tostring(sv)
        else
          sv = nil
        end
      end
      -- replace destination value
      if sv ~= nil and dv ~= sv then
        d[k] = sv
        n = n + 1
      end
    end
  end
  return n
end
It works similar to "table.copy" but it only overwrites existing values so:

Code: Select all

default = { 1, 2, 3 }

current = {}
table.replace(default, current) -- does nothing since the destination table has no values that can be replaced
current = { 4, 5, 6 }
table.replace(default, current) -- replaces "4, 5, 6" with "1, 2, 3"
If your "player" table includes functions then why not:

Code: Select all

local player = {}
local playermt = { __index = player }

function player:create()
  local self = {}
  setmetatable(self, playermt)
  self:reset()
  return self
end

function player:reset()
  self.x = 10
  self.y = 636
  self.width = 80
  self.height = 80
  -- etc
end
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Resetting a table back to it's original values

Post by Robin »

Note that ivan's copy functions crash if you pass a table with cycles.

Now, what you probably want is none of this, but just a reset function:

Code: Select all

player = {}

function player.Reset()
   player.x = 10
   player.y = 636
   player.width = 80
   player.height = 80
   player.speed = 300
   player.xVel = 0
   player.yVel = 0
   player.jumpVel = -800
   player.score = 0
   player.lives = 3
   player.state = "stand"
end

player.Reset()
Then you can simply call player.Reset().
Help us help you: attach a .love.
User avatar
rmcode
Party member
Posts: 454
Joined: Tue Jul 15, 2014 12:04 pm
Location: Germany
Contact:

Re: Resetting a table back to it's original values

Post by rmcode »

I also prefer Robin's method. It's simple and it works. You could store the default values in "constants" at the top of your class. That way you only have to change them in one place later on.

Code: Select all

local HEALTH = 300;
local PLAYER_X = 10;
local PLAYER_Y = 636;

player = {
   x = PLAYER_X,
   y = PLAYER_Y,
   ...
}

function player.reset()
     player.x = PLAYER_X;
     player.y = PlAYER_Y;
     ...
end
kotwarrior
Prole
Posts: 2
Joined: Thu Oct 02, 2014 3:17 am

Re: Resetting a table back to it's original values

Post by kotwarrior »

You could also try and set the original table as a metatable of the given table, just cache it using this function:

Code: Select all

local cache = function(tab)
local extra = tab;
setmetatable(tab, extra);
end;
and retrieve it using this one:

Code: Select all

local retrieve = function(tab)
return getmetatable(tab);
end;
To access these functions, you can use:

Code: Select all

local item = {"plr"; "important data";};
cache(item);
local item = {};
-- to retrieve
local item = retrieve(item);
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Resetting a table back to it's original values

Post by Robin »

That... doesn't work. Like, at all.
Help us help you: attach a .love.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Resetting a table back to it's original values

Post by kikito »

I need to point out that you actually don't need to reset the table to its original values. Like, at all. Just return a new table and override the old one.

Code: Select all

local player
...
function newPlayer()
  return {
    x = 10,
    y = 636,
    width = 80,
    ...
    state = "stand"
  }
end
Every time you need to "reset" the player you can do this:

Code: Select all

player = newPlayer()
Coding this way (creating new values instead of reusing existing ones) has less problems than what you are doing - for example, it's much more difficult to "forget resetting one value". It's also not possible to "get old values from the previous game" if you destroy and recreate everything.
When I write def I mean function.
Clouds
Prole
Posts: 23
Joined: Tue Nov 27, 2012 4:06 am

Re: Resetting a table back to it's original values

Post by Clouds »

kikito wrote:I need to point out that you actually don't need to reset the table to its original values. Like, at all. Just return a new table and override the old one.
....
Coding this way (creating new values instead of reusing existing ones) has less problems than what you are doing - for example, it's much more difficult to "forget resetting one value". It's also not possible to "get old values from the previous game" if you destroy and recreate everything.
Maybe it's good practice anyway, but if you do this, you have to also code the rest of your program to never ever set another variable to point to the table in question (unless it's always re-set before use). A new table, being a new object, won't update old references to the original table.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Resetting a table back to it's original values

Post by kikito »

Clouds wrote:Maybe it's good practice anyway, but if you do this, you have to also code the rest of your program to never ever set another variable to point to the table in question (unless it's always re-set before use). A new table, being a new object, won't update old references to the original table.
No, you can have references to variables. It's just that your code needs to (re)assigns them when they need to be "reset". I think this is a good practice.
When I write def I mean function.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest