Why my loop only occurs twice and the same items are chosen?

-- Fired when player joins
for i = 1, 3 do
	TaskService:AssignTask(player)
end

-- TaskData
return {
	['Visit the Pizzera!'] = {Coins = 10, Exp = 8},
	['Play the pizzeria minigame!'] = {Coins = 5, Exp = 5},
	['Buy some furniture!'] = {Coins = 5, Exp = 5},
}

function TaskService:AssignTask(player)
	if PlayerTasks[player.UserId] then
		print(#PlayerTasks[player.UserId], unpack(PlayerTasks[player.UserId]))
		if #PlayerTasks[player.UserId] >= 3 then return end

		for i, v in pairs(TaskData) do
			for _, currentTask in pairs(PlayerTasks[player.UserId]) do
				-- Check if task is already assigned
				if i == currentTask then break end

				table.insert(PlayerTasks[player.UserId], i)
				
				return
			end
		end
		
		return
	else
		for i, v in pairs(TaskData) do
			PlayerTasks[player.UserId] = {}
			table.insert(PlayerTasks[player.UserId], i)
			
			return
		end
	end
end

Output
1 Visit the Pizzera!

2 Visit the Pizzera! Play the pizzeria minigame!

Should be adding 3 items, not 2? And why is it the same 2 items every time? It should be picking 3 at random (ik at the moment I only have 3 in the table, but I plan on adding more)

1 Like

As you can see, you declared the table(dictionary) and it is in the fixed order. Perhaps you should add a shuffle function.

Why it only prints twice is because the items were not added yet. As you can see, the first iteration gave it the 1 Visit the Pizzeria, but never printed. The second loop printed it, because the table now exists and adds up the 2nd value. However, the third value print was skipped, because the print is placed at the very top of the script, now prints 2 Visit the Pizzeria! Play the pizzeria minigame!.

In other words, try setting the printing functionality at the very bottom of the function or outside the function. Returns prevent it from printing, and perhaps it is advised to restructure it a little.

I thought I had added a math.random in there some where, obviously not :sweat_smile: would math.random work fine tho? Or should I use this ‘shuffle function’ you speak of? (not entirely sure what that is?)

Hmm, you just reminded me that you could also do:
table.insert(table, math.random(#table), value)

Which in my case would look like??

table.insert(PlayerTasks[player.UserId], math.random(#PlayerTasks[player.UserId]), i)

This wouldnt work if they haven’t got a table yet tho

for i, v in pairs(TaskData) do
			PlayerTasks[player.UserId] = {}
			table.insert(PlayerTasks[player.UserId], math.random(#PlayerTasks[player.UserId]), i)
			
			return
		end

bad argument #1 (interval is empty)
on the table.insert line

Do not do it when the table is empty, leave that field empty. Since interval is empty, it is obvious you shouldn’t be changing the second elseif block.

Problem is then for their first task they are always gonna get the first option in the TaskData

You should somehow shuffle the dictionary, which could be taking only an extra step to do so. Alternatively, shuffling the index choices. You will need:

  • Strings in an array
  • Randomizing a pick from the array
  • Getting the task information after duplicate checks

What’s the point of putting ‘return’ inside the loops? This stops the iteration completely so the loops make no sense.

I think it might be because you’re breaking it when it gets to the current one? It’s just a guess but wouldn’t want to leave any possibility unmentioned.

EDIT: I’m saying, maybe its because of this, sorry for any confusion.
image

Slightly confused…

local TaskArray = {
	"Visit the Pizzeria!"; "Play the pizzeria minigame!"; "Buy some furnitures!"
}

local function shufflePick(t)
	return TaskData[TaskArray[math.random(#TaskArray)]]
end

The practice goes something along the lines of this.

@Humanagon The break prevents duplicates.

I have already given you something similiar. The topping selection algorithm can also be used to work in this case. Consistently get random selections - #2 by Kacper

@Operatik I just looked at for quite a bit. I see what you’re saying but if it was to prevent duplicates, wouldn’t it be ~= instead of ==? I’m a relatively new scripter so correct me if I’m wrong, but to me it looks like the reason it’s printing the two and not the three is because it’s breaking when its on the current task, not when it’s on the others. Maybe that’s why it only prints the 2, because it does 2 at first, then when it gets to the last one, it just breaks because it’s the current one and doesn’t print?

Unfortunately, it should be ==, because you’re matching the pre-made information with the created information. If there are matches, it would not insert the new information.

Also it is irrelevant about the printing currently. As aforementioned, I have clarified that there was only two prints and both prints indicate the contents before insertion.

So if it’s not the break, and it’s not an incorrect symbol, what’s making it stop? I’m looking at it from every angle possible and I can’t figure out anything else. :joy:

It is a logical error. Analyze the code and see that…:

  • the first iteration, nothing prints, index inserted
  • the second iteration, first index printed, second index inserted
  • the third iteration, two index printed, third index inserted(not printed)

Ohhhhh so it’s because nothing is inserted before it prints, so it just prints nil?

No. That’s because the print function is not inside the second block of elseif statement. If there was nil, it would’ve been printed nil.

Ok I think I see what you mean. You’re saying that there should of been a print here?
image

EDIT: Ok if this isn’t it then I have no idea what you’re trying to hint at.