Getting random item in a table for a game - lua

local limiteds = {
test1 = {
value = 999999999,
itemid = -1,
released = false
}
}
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
function randomitem()
local limited
repeat
local limited = limiteds[math.random(tablelength(limiteds))]
until limited.released == false
end
but it is crashing my game at the repeat loop and I cant figure out why. limited seems to be nil for some odd reason?

function randomitem()
local limited
repeat
local key
for i = 1, math.random(tablelength(limiteds)) do
key, limited = next(limiteds, key)
end
until limited.released == false
return limited
end

Related

Lua function constantly returning false out of SQL function

I have this code
function IsAuthorized(xPlayer, doorID, locked, usedLockpick)
local jobName, grade = {}, {}
jobName[1] = xPlayer.job.name
grade[1] = xPlayer.job.grade
if xPlayer.job2 then
jobName[2] = xPlayer.job2.name
grade[2] = xPlayer.job2.grade
end
local canOpen = false
if doorID.lockpick and usedLockpick then
count = xPlayer.getInventoryItem('lockpick').count
if count and count >= 1 then canOpen = true end
end
if not canOpen and doorID.authorizedJobs then
for job,rank in pairs(doorID.authorizedJobs) do
if (job == jobName[1] and rank <= grade[1]) or (jobName[2] and job == jobName[2] and rank <= grade[2]) then
canOpen = true
if canOpen then break end
end
end
end
if not canOpen and doorID.items then
local count
for k,v in pairs(doorID.items) do
count = xPlayer.getInventoryItem(v).count
if count and count >= 1 then
canOpen = true
local consumables = { ['ticket']=1 }
if locked and consumables[v] then
xPlayer.removeInventoryItem(v, 1)
end
break
end
end
if not count or count < 1 then canOpen = false end
end
if not canOpen then
local group = xPlayer.getGroup()
if group == 'management' or group == 'owner' then
print(group..' '..xPlayer.getName()..' was authorised to use a door')
canOpen = true
end
if doorID.authorizedgang then
print(xPlayer.identifier .. " | " .. doorID.authorizedgang)
MySQL.Async.fetchSingle('SELECT * FROM users WHERE identifier = ? AND gang = ?', {xPlayer.identifier, doorID.authorizedgang}, function(foundplayer)
if foundplayer then
print("found")
canOpen = true
print(canOpen)
end
----------------------------canopen returns true until here
end)
end
end
print(canOpen)
return canOpen
end
Essentially what is does is return a true or false value based on the if statements. I did not write this script myself, I simply added on. The code that I added to this function is
if doorID.authorizedgang then
print(xPlayer.identifier .. " | " .. doorID.authorizedgang)
MySQL.Async.fetchSingle('SELECT * FROM users WHERE identifier = ? AND gang = ?', {xPlayer.identifier, doorID.authorizedgang}, function(foundplayer)
if foundplayer then
print("found")
canOpen = true
print(canOpen)
end
----------------------------canopen returns true until here
end)
end
This code essentially makes a database call to check if it'll find a player with X identifier and Y gang, and this actually does work because it prints out "found" and canOpen returns true until the line that I marked, after this it returns false at the bottom of the function.
I've been trying other ways to get the data but ultimately I need the SQL DB call for this and im not sure why the variable isnt setting when in fact the database returns found. Any ideas what I could be doing wrong here?

Why does this Int Value keep coming back after it is set? [Roblox Studio]

I'm sorry if this is a really simple or easy question, but I am trying to set the player leaderstat "Money" to 0, but it keeps coming back as the old value. The only thing that I can think of that may be causing this problem is that the moneyGain script is on repeat.
Here is my moneyGain script:
local playerMoney
while wait(0.24) do
local buttons = script.Parent.Parent.info.savedItems.Value.buttons:GetChildren()
for button = 1, #buttons, 1 do
if buttons[button].Parent.Parent.tycoon.Value ~= nil then
if buttons[button].Parent.Parent.tycoon.Value.info.owner ~= nil then
if buttons[button].jobDone.Value == true then
script.Parent.moneyEnforcer.enforce:Invoke(buttons[button].gainVal.Value)
end
end
end
end
--OWNERDOOR:
if script.Parent.Parent.info.owner.Value ~= nil then
script.Parent.moneyEnforcer.enforce:Invoke(1)
end
end
Here is my moneyEnforcer script:
local rs = game:GetService("ReplicatedStorage")
local dictionary = require(rs.dictionary)
local vipPlayers = dictionary.vipPlayers
script.enforce.OnInvoke = function(amount)
print(amount)
if script.Parent.Parent.info.player.Value ~= nil then
if game:GetService("GamePassService"):PlayerHasPass(script.Parent.Parent.info.player.Value, 25494219) then
amount = amount * 2
else
for i = 1, #vipPlayers, 1 do
if script.Parent.Parent.info.player.Value.Name == vipPlayers[i] then
amount = amount * 2
end
end
end
local playerMoney = script.Parent.Parent.info.player.Value.leaderstats.Money
script.Parent.Parent.info.player.Value.leaderstats.Money.Value = script.Parent.Parent.info.player.Value.leaderstats.Money.Value + amount
end
end
And here is the tycoon reseter:
local player = script.Parent.Parent.Parent.Parent.Parent.Parent
script.Parent.Parent.Parent.Visible = false
script.Parent.MouseButton1Click:Connect(function()
player.leaderstats.Money.Value = 0
script.Parent.Parent.Parent.Visible = false
local savedItems = player.claimedTycoon.Value.info.savedItems.Value
local builds = player.claimedTycoon.Value.activeBuilds:GetChildren()
local buttons = player.claimedTycoon.Value.activeButtons:GetChildren()
for i = 1, #builds, 1 do
builds[i].Parent = savedItems.builds
end
for j = 1, #buttons, 1 do
buttons[j].Parent = savedItems.buttons
end
savedItems.builds.dirtStarterBase.Parent = player.claimedTycoon.Value
player.claimedTycoon.Value.info:WaitForChild("activeWave").Value = 1
end)
I have tried putting the "script.Parent.Parent.info.player.Value.leaderstats.Money.Value = script.Parent.Parent.info.player.Value.leaderstats.Money.Value + amount" on the moneyGain script, but that made no difference.
Any help is appriciated!
I believe your problem is that you're setting the value of money from the client. When you change the value from a local script, it will not update on the server. To fix this update the value from the server
In tycoon reseter, try resetting the value from the server using a RemoteEvent

Why does Roblox & Roblox Studio both crash when running certain scripts with no error code?

So here's the deal, I'm working on a game that is similar to a murder mystery and this part of the system is to start the round and show the players their roles and then the map. Except it used to work and I didn't knowingly do anything to the scripts that would affect it so the game crashes when this part is carried out. All I know is it starts to display the role and often does, it also plays the sound and displays the correct description, however it crashes just after that and sometimes just before the role is revealed. I've attached the function that runs when the RoundStarter event is fired to the client.
The server doesn't crash but, all of the clients do but not all at the exact same moment in time; Previously when there has been errors, I've been able to identify an error message but none of the clients throw any clear issues.
In testing mode in Roblox Studio, they freeze just after the drum roll sound effect as the role is displayed, however no errors and the server seems to be acting normally. Near enough the same thing happens when ran in Roblox.
Clientside script
ReplicatedStorage.Players.Events.RoundStarter.OnClientEvent:Connect(function(Role,Map)
local player = game.Players.LocalPlayer
player.CameraMode = Enum.CameraMode.LockFirstPerson
script.Parent.RoundGui.RoundEnd.Visible = false
game.Players.LocalPlayer.NameDisplayDistance = 0
CURRENTROLE = Role
CURRENTMAP = Map
script.Parent.RoundGui.Enabled = true
script.Parent.RoundGui.RoundStarter.Visible = true
script.Parent.RoundGui.RoundStarter.Fader.Visible = true
script.Parent.RoundGui.RoundStarter.Fader.BackgroundTransparency = 0
script.Parent.RoundGui.RoundStarter.RoleDescription.Visible = false
script.Parent.RoundGui.RoundStarter.RoleName.Visible = false
script.Parent.RoundGui.RoundStarter.Text.Visible = true
local transp = 0
for i = 1,50,1 do
transp += 0.05
script.Parent.RoundGui.RoundStarter.Fader.BackgroundTransparency = transp
wait(.1)
end
script.Parent.RoundGui.RoundStarter.DR:Play()
script.Parent.RoundGui.RoundStarter.RoleName.Visible = true
script.Parent.RoundGui.RoundStarter.RoleName.Text = Role
script.Parent.RoundGui.RoundStarter.RoleDescription.Visible = true
if Role == "Civilian" then
script.Parent.RoundGui.RoundStarter.RoleDescription.Text = "Your Job is to help the Inspector find the shadow... Work to figure them out and stop them before it's too late! Don't tell anyone your Role!"
script.Parent.RoundGui.RoundStarter.RoleName.TextColor3 = Color3.fromRGB(0, 255, 17)
elseif Role == "Shadow" then
script.Parent.RoundGui.RoundStarter.RoleName.TextColor3 = Color3.fromRGB(255, 0, 0)
script.Parent.RoundGui.RoundStarter.RoleDescription.Text = "It's time... Infiltrate the crowd, gain their trust and kill the inspector to win! By killing another player, You can take on their form and blend in with the Civilians. More help will be on left of the screen. Don't tell anyone your Role!"
elseif Role == "Inspector" then
script.Parent.RoundGui.RoundStarter.RoleName.TextColor3 = Color3.fromRGB(0, 38, 255)
script.Parent.RoundGui.RoundStarter.RoleDescription.Text = "You are nominated to fight the Shadow and eliminate them. You must work with the Civilians to figure out who the Shadow is, if you die you lose. Don't tell anyone your Role!"
end
wait(10)
script.Parent.RoundGui.RoundStarterMap.Visible = true
script.Parent.RoundGui.RoundStarterMap.Fader.Visible = true
script.Parent.RoundGui.RoundStarterMap.MapDescription.Visible = false
script.Parent.RoundGui.RoundStarterMap.MapName.Visible = false
local transp = 0
for i = 1,50,1 do
transp += 0.05
script.Parent.RoundGui.RoundStarterMap.Fader.BackgroundTransparency = transp
wait(.1)
end
script.Parent.RoundGui.RoundStarterMap.MapName.Visible = true
script.Parent.RoundGui.RoundStarterMap.MapName.Text = Map
script.Parent.RoundGui.RoundStarter.Dun:Play()
if Map == "The Office" then
script.Parent.RoundGui.RoundStarterMap.MapDescription.Text = "A classic map based in an Office building, in a power cut, near midnight. With an outdoor and Indoor area to explore, will you survive?"
elseif Map =="The Village" then
script.Parent.RoundGui.RoundStarterMap.MapDescription.Text = "The original map based in a small villiage with numerous buildings and areas to explore."
end
script.Parent.RoundGui.RoundStarterMap.MapDescription.Visible = true
wait(10)
script.Parent.RoundGui.RoundEnd.Visible = false
script.Parent.RoundGui.RoundStarterMap.Visible = false
script.Parent.RoundGui.RoundStarter.Visible = false
end)
--This is the next function in the code that should be executed at a similar time to the above one (It should have an InMap value of true.
ReplicatedStorage.Players:WaitForChild(player.Name).InMap.Changed:Connect(function()
data = game.ReplicatedStorage.GetPlayerDataCS:InvokeServer()
if ReplicatedStorage.Players[player.Name].InMap.Value == false then
--StartGUI:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, true)
player.CameraMode = Enum.CameraMode.Classic
--StartGUI:SetCoreGuiEnabled(Enum.CoreGuiType.Chat,true)
script.Parent.LobbyGui.Enabled = true
script.Parent.RoundGui.Enabled = false
wait()
else
if CURRENTROLE == "Shadow" then
script.Parent.RoundGui.ShadowPanel.Visible = true
script.Parent.RoundGui.CivPanel.Visible = false
script.Parent.RoundGui.InsPanel.Visible = false
if data then
if data.EquippedAbility ~="None" and data.EquippedAbility ~="" then
script.Parent.RoundGui.ShadowPanel[data.EquippedAbility].Visible = true
end
end
elseif CURRENTROLE == "Inspector" then
script.Parent.RoundGui.ShadowPanel.Visible = false
script.Parent.RoundGui.CivPanel.Visible = false
script.Parent.RoundGui.InsPanel.Visible = true
else
script.Parent.RoundGui.ShadowPanel.Visible = false
script.Parent.RoundGui.CivPanel.Visible = true
script.Parent.RoundGui.InsPanel.Visible = false
end
--StartGUI:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, false)
--StartGUI:SetCoreGuiEnabled(Enum.CoreGuiType.Chat,true)
script.Parent.LobbyGui.Enabled = false
script.Parent.RoundGui.Enabled = true
wait()
end
end)
Here's also the script on the server that should be near the event.
local replicatedstor = game:GetService("ReplicatedStorage")
local playersinthemap = {}
local playersinserver = game.Players:GetPlayers()
local maplist = {"The Village"}
local TESTINGMODE = false
local goodwin = false
local COUNT = 0
local deadpool = {}
local DataStoreService = game:GetService("DataStoreService")
local Datastore = DataStoreService:GetDataStore("THE_MASQUERADE_TEST2")
function UpdateStatuses(Playerr,NewStatus)
local c = Playerr
if NewStatus == "Lobby" or NewStatus == "AFK" then
if game.ReplicatedStorage.Players[c.Name].Status.Value == "Shadow" then
script.RoundsInProgress.Value = false
goodwin = true
elseif game.ReplicatedStorage.Players[c.Name].Status.Value == "Inspector" then
script.RoundsInProgress.Value = false
goodwin = false
end
game.ReplicatedStorage.Players[c.Name].InMap.Value = false
if table.find(playersinthemap,c,1)~= nil then
local index = table.find(playersinthemap,c,1)
table.remove(playersinthemap,index)
end
end
game.ReplicatedStorage.Players[c.Name].Status.Value = NewStatus
if #playersinthemap <= 2 and script.RoundsInProgress.Value == true then
script.RoundsInProgress.Value = false
goodwin = false
end
end
game.ReplicatedStorage.Players.Events.SetStatus.OnServerEvent:Connect(function(Player,Status)
if Status ~= nil then
UpdateStatuses(Player,Status)
else
print ("Tried to change status of Player but the given status was nil.")
end
end)
while true do
while script.RoundsRunning.Value == true do
game.ReplicatedStorage.Players.Events.Notify:FireAllClients("Intermission...","L",false)
--game.ReplicatedStorage.Game.Intermission:Fire(30)
--game.ReplicatedStorage.Game.Intermission.Event:Wait()
wait(35)
game.Workspace.Lobby.DATABOARD.SurfaceGui.Frame.Title.Text = "Round starting soon..."
--game.ReplicatedStorage.Players.Events.Notify:FireAllClients("Round starting soon...","L",true)
--game.Workspace.Lobby.DATABOARD.SurfaceGui.Frame.Time.Text = ""
if not game.Workspace.Map then
playersinthemap = {}
local Mapfolder = Instance.new("Folder",game.Workspace)
Mapfolder.Name = "Map"
end
playersinserver = game.Players:GetPlayers()
wait(10)
playersinserver = game.Players:GetPlayers()
if #playersinserver >= 4 or (TESTINGMODE == true and #playersinserver >= 3) then
game.Workspace.Lobby.DATABOARD.SurfaceGui.Frame.Title.Text = "Round loading..."
game.ReplicatedStorage.Players.Events.Notify:FireAllClients("Loading the round now...","L",false)
playersinserver = game.Players:GetPlayers()
local chosenMapIndex = math.random(#maplist)
local chosenMapName = maplist[chosenMapIndex]
local chosenShadowIndex = math.random(#playersinserver)
local chosenShadow = playersinserver[chosenShadowIndex]
local chosenInspectorIndex = math.random(#playersinserver)
local chosenInspector = playersinserver[chosenInspectorIndex]
while chosenInspector == chosenShadow do
chosenInspectorIndex = math.random(#playersinserver)
chosenInspector = playersinserver[chosenInspectorIndex]
end
local playernumber = playersinserver
COUNT = 0
while COUNT ~= #playersinserver do
COUNT += 1
local playername = playersinserver[COUNT].Name
print (playersinserver)
print ("Player trying to send role data:"..playername)
if playersinserver[COUNT] == chosenShadow then
game.ReplicatedStorage.Players.Events.RoundStarter:FireClient(playersinserver[COUNT],"Shadow",chosenMapName)
game.ReplicatedStorage.Players[playersinserver[COUNT].Name].Status.Value = "Shadow"
--temp = game.ReplicatedStorage.ReadStatus:Invoke(playername,"Shadow")
elseif playersinserver[COUNT] == chosenInspector then
game.ReplicatedStorage.Players.Events.RoundStarter:FireClient(playersinserver[COUNT],"Inspector",chosenMapName)
game.ReplicatedStorage.Players[playersinserver[COUNT].Name].Status.Value = "Inspector"
--temp = game.ReplicatedStorage.ReadStatus:Invoke(playername,"Inspector")
else
game.ReplicatedStorage.Players.Events.RoundStarter:FireClient(playersinserver[COUNT],"Civilian",chosenMapName)
game.ReplicatedStorage.Players[playersinserver[COUNT].Name].Status.Value = "Civilian"
--temp = game.ReplicatedStorage.ReadStatus:Invoke(playername,"Civilian")
end
end
wait()
local MapInServerStorage = game.ServerStorage.Maps:FindFirstChild(chosenMapName)
local LoadedMap = MapInServerStorage:Clone()
LoadedMap.Parent = game.Workspace.Map
local spawns = {}
for i,c in pairs(LoadedMap:GetDescendants()) do
if c.Name == "Spawn" then
table.insert(spawns,1,c)
end
end
COUNT = 0
local i = COUNT
while COUNT ~= #playersinserver do
COUNT += 1
print ("Setting Character locations. Loop:"..COUNT)
local spawnlistindex = math.random(#spawns)
playersinserver[COUNT].Character:SetPrimaryPartCFrame(spawns[spawnlistindex].CFrame)
--playersinserver[COUNT].Character:SetPrimaryPartCFrame(LoadedMap.Spawns.Spawn.CFrame)
table.insert(playersinthemap,1,playersinserver[COUNT])
playersinserver[COUNT].NameDisplayDistance = 0
game.ReplicatedStorage.Players:FindFirstChild(playersinserver[COUNT].Name).InMap.Value = true
if playersinserver[COUNT] == chosenInspector then
local data = game.ReplicatedStorage.GetPlayerData:Invoke(chosenInspector)
Pistl = game.ServerStorage.Guns[data.EquippedSkin]:Clone()
Pistl.Parent = playersinserver[COUNT].Backpack
end
end
print ("Round starting...")
--This is then followed by the rest of the round system which should be working but I have cut it to try to shorten the amount of reading but can be supplied if needed. It is closed correctly.
I've tried to keep the code to a minimum however it could be anywhere and as there are no obvious script related error codes, I'm requesting some assistance in some way.
There are other things that may have caused it but this is becoming a real issue, especially since it used to work, and I've included all of the likely suspects but I'm happy to give anything else if these aren't incorrect in anyway.
If you wish to see what happens yourself, you'll need either 4 Roblox Accounts or 3 extra friends.
Here's the game on Roblox: The Masquerade
If anything else is needed, feel free to let me know and thanks for reading and any potential help. (Just so you know, I have done a lot of research on all of the functions and things I'm using but I can't find any issues, it just freezes & crashes).
The only error codes I've got are:
Start Process Exception...
Uploading crash analytics
Done uploading crash analytics
There are some random wait() statements without any arguments, which shouldn't be in your code anyway. This may very well hang up the server / client.
Also, you appear to have a few while loops which do not have any wait()'s. That's a pretty common problem which stalls the client executing the script. Try adding at least
wait(0.01) to the end of each while true loop that doesn't have it already.
There might be some occurences of this in the client as well (like that one lonely wait() with no parameters), but here's a modified version of your server script:
while true do
while script.RoundsRunning.Value == true do
game.ReplicatedStorage.Players.Events.Notify:FireAllClients("Intermission...","L",false)
--game.ReplicatedStorage.Game.Intermission:Fire(30)
--game.ReplicatedStorage.Game.Intermission.Event:Wait()
wait(35)
game.Workspace.Lobby.DATABOARD.SurfaceGui.Frame.Title.Text = "Round starting soon..."
--game.ReplicatedStorage.Players.Events.Notify:FireAllClients("Round starting soon...","L",true)
--game.Workspace.Lobby.DATABOARD.SurfaceGui.Frame.Time.Text = ""
if not game.Workspace.Map then
playersinthemap = {}
local Mapfolder = Instance.new("Folder",game.Workspace)
Mapfolder.Name = "Map"
end
playersinserver = game.Players:GetPlayers()
wait(10)
playersinserver = game.Players:GetPlayers()
if #playersinserver >= 4 or (TESTINGMODE == true and #playersinserver >= 3) then
game.Workspace.Lobby.DATABOARD.SurfaceGui.Frame.Title.Text = "Round loading..."
game.ReplicatedStorage.Players.Events.Notify:FireAllClients("Loading the round now...","L",false)
playersinserver = game.Players:GetPlayers()
local chosenMapIndex = math.random(#maplist)
local chosenMapName = maplist[chosenMapIndex]
local chosenShadowIndex = math.random(#playersinserver)
local chosenShadow = playersinserver[chosenShadowIndex]
local chosenInspectorIndex = math.random(#playersinserver)
local chosenInspector = playersinserver[chosenInspectorIndex]
while chosenInspector == chosenShadow do
chosenInspectorIndex = math.random(#playersinserver)
chosenInspector = playersinserver[chosenInspectorIndex]
end
local playernumber = playersinserver
COUNT = 0
while COUNT ~= #playersinserver do
COUNT += 1
local playername = playersinserver[COUNT].Name
print (playersinserver)
print ("Player trying to send role data:"..playername)
if playersinserver[COUNT] == chosenShadow then
game.ReplicatedStorage.Players.Events.RoundStarter:FireClient(playersinserver[COUNT],"Shadow",chosenMapName)
game.ReplicatedStorage.Players[playersinserver[COUNT].Name].Status.Value = "Shadow"
--temp = game.ReplicatedStorage.ReadStatus:Invoke(playername,"Shadow")
elseif playersinserver[COUNT] == chosenInspector then
game.ReplicatedStorage.Players.Events.RoundStarter:FireClient(playersinserver[COUNT],"Inspector",chosenMapName)
game.ReplicatedStorage.Players[playersinserver[COUNT].Name].Status.Value = "Inspector"
--temp = game.ReplicatedStorage.ReadStatus:Invoke(playername,"Inspector")
else
game.ReplicatedStorage.Players.Events.RoundStarter:FireClient(playersinserver[COUNT],"Civilian",chosenMapName)
game.ReplicatedStorage.Players[playersinserver[COUNT].Name].Status.Value = "Civilian"
--temp = game.ReplicatedStorage.ReadStatus:Invoke(playername,"Civilian")
end
end
-- wait() useless wait
local MapInServerStorage = game.ServerStorage.Maps:FindFirstChild(chosenMapName)
local LoadedMap = MapInServerStorage:Clone()
LoadedMap.Parent = game.Workspace.Map
local spawns = {}
for i,c in pairs(LoadedMap:GetDescendants()) do
if c.Name == "Spawn" then
table.insert(spawns,1,c)
end
end
COUNT = 0
local i = COUNT
while COUNT ~= #playersinserver do
COUNT += 1
print ("Setting Character locations. Loop:"..COUNT)
local spawnlistindex = math.random(#spawns)
playersinserver[COUNT].Character:SetPrimaryPartCFrame(spawns[spawnlistindex].CFrame)
--playersinserver[COUNT].Character:SetPrimaryPartCFrame(LoadedMap.Spawns.Spawn.CFrame)
table.insert(playersinthemap,1,playersinserver[COUNT])
playersinserver[COUNT].NameDisplayDistance = 0
game.ReplicatedStorage.Players:FindFirstChild(playersinserver[COUNT].Name).InMap.Value = true
if playersinserver[COUNT] == chosenInspector then
local data = game.ReplicatedStorage.GetPlayerData:Invoke(chosenInspector)
Pistl = game.ServerStorage.Guns[data.EquippedSkin]:Clone()
Pistl.Parent = playersinserver[COUNT].Backpack
end
wait(0.01)
end
wait(0.01)
end
These are just the rough steps, so implant the changes in your code the way you want them to be.

How to implement the exercise 15.5 in pil4?

I am working on this exercise in pil4.
Exercise 15.5:
The approach of avoiding constructors when saving tables with cycles is too radical. It is
possible to save the table in a more pleasant format using constructors for the simple case, and to use
assignments later only to fix sharing and loops. Reimplement the function save (Figure 15.3, “Saving
tables with cycles”) using this approach. Add to it all the goodies that you have implemented in the previous
exercises (indentation, record syntax, and list syntax).
I have tried this with the code below, but it seems not to work on the nested table with a string key.
local function basicSerialize(o)
-- number or string
return string.format("%q",o)
end
local function save(name,value,saved,indentation,isArray)
indentation = indentation or 0
saved = saved or {}
local t = type(value)
local space = string.rep(" ",indentation + 2)
local space2 = string.rep(" ",indentation + 4)
if not isArray then io.write(name," = ") end
if t == "number" or t == "string" or t == "boolean" or t == "nil" then
io.write(basicSerialize(value),"\n")
elseif t == "table" then
if saved[value] then
io.write(saved[value],"\n")
else
if #value > 0 then
if indentation > 0 then io.write(space) end
io.write("{\n")
end
local indexes = {}
for i = 1,#value do
if type(value[i]) ~= "table" then
io.write(space2)
io.write(basicSerialize(value[i]))
else
local fname = string.format("%s[%s]",name,i)
save(fname,value[i],saved,indentation + 2,true)
end
io.write(",\n")
indexes[i] = true
end
if #value > 0 then
if indentation > 0 then io.write(space) end
io.write("}\n")
else
io.write("{}\n")
end
saved[value] = name
for k,v in pairs(value) do
if not indexes[k] then
k = basicSerialize(k)
local fname = string.format("%s[%s]",name,k)
save(fname,v,saved,indentation + 2)
io.write("\n")
end
end
end
else
error("cannot save a " .. t)
end
end
local a = { 1,2,3, {"one","Two"} ,5, {4,b = 4,5,6} ,a = "ddd"}
local b = { k = a[4]}
local t = {}
save("a",a,t)
save("b",b,t)
print()
And I got the wrong ouput.
a = {
1,
2,
3,
{
"one",
"Two",
}
,
5,
{
4,
5,
6,
}
a[6]["b"] = 4
,
}
a["a"] = "ddd"
b = {}
b["k"] = a[4]
How could I make the text ' a[6]["b"] = 4 ' jump out of the table constructor?

How to properly and efficiently shuffle a table's contents?

I'm trying to shuffle a table's contents randomly. It works fine, except sometimes it doesn't return all the contents of the table. I printed out some of the keys of the table before shuffling, and they returned nil, but I'm not sure how to fix that. Here's the Lua:
local tab = {1,2,3,4,5,6,7,8,9,10}
function ReturnRandomTable(t)
local newt = {}
local i = 1
repeat
local rand = math.random(1,#t)
newt[i] = t[rand]
print(t[rand]) --sometimes prints nil
t[rand] = nil
i = i + 1
until #t == 0
return newt
end
table.shuffle = function(t)
local newt = ReturnRandomTable(t)
for i = #t,1,-1 do
t[i] = nil
end
return newt
end
local randt = table.shuffle(tab)
for _,v in pairs(randt) do
print(v)
end
Any help would be appreciated!
Solved by changing t[rand] = nil to table.remove(t,rand).

Resources