ID:139815
 
I am trying to make a shuffle system for a card game and getting an annoying issue with this.
Code:
proc/PileRandom(list/TheDeck)
var
list/piles[6]
list/newdeck[]
ii=0
pilenum=0
CardNum=0
while(TheDeck.len>0)
ii++
pilenum=ii%6
if(pilenum==0) pilenum=6
CardNum=rand(1,TheDeck.len)
piles[pilenum].Add(TheDeck[CardNum])
TheDeck.Cut(CardNum, CardNum+1)
while(piles.len>0)
pilenum = rand(1,piles.len)
newdeck+=piles[pilenum]
piles.Cut(pilenum,pilenum+1)
TheDeck.Cut()
TheDeck.Add(newdeck)


Problem description:
piles[pilenum].Add(TheDeck[CardNum]) error: .: expected end of statement

The same thing happens with all of the built-inlist procs;
Add, Copy, Cut, Find, Insert, Remove & Swap
Unlike some other languages BYOND does not know if something such as this is actually a list at compile-time, since it's really not until runtime, so you have to tell it.

var/list/pile_list = piles[pile_num]
if(pile_list&&istype(pile_list,/list)) // Double-checking.
pile_list.Cut(...)


That's how it's done.
In response to Nadrew
So in order to do what I want to do I have to make a temporary list, do the changes to it.
But then how do I put those changes back in? just do

var/list/pile_list = piles[pile_num]
if(pile_list&&istype(pile_list,/list)) // Double-checking.
pile_list.Add(TheDeck[CardNum])
piles[pilenum] = pile_list
?
In response to Bunnie
That's the beauty of lists, they're datums, so if you set a variable to the list it becomes a direct reference to that list, not a new list.


var/list/A = list("A","B","C")

var/list/B = A
B.Remove("A")

for(var/item in A)
src << item // Will output "B" and "C", but not "A".


So when you set the variable you're effectively setting it to the list itself, not a copy of it. This is the main reason the Copy() function exists, so you can duplicate a list easily, since using = will just set a reference.

In summary, anything you do to the variable you set the list to will affect the list directly and no further action is required. Doesn't use any extra list space or memory, since you're never actually creating anything new (except the variable itself)
In response to Nadrew
Thank you although now I'm with a new issue...

proc/PileRandom(list/TheDeck)
var
list
piles[6]
newdeck[]
PileAdd
ii=0
pilenum=0
CardNum=0
while(TheDeck.len>0)
ii++
pilenum=ii%6
if(pilenum==0) pilenum=6
CardNum=rand(1,TheDeck.len)
PileAdd = piles[pilenum]
if(PileAdd&&istype(PileAdd,/list)) PileAdd.Add(TheDeck[CardNum])
TheDeck.Cut(CardNum, CardNum+1)
while(piles.len>0)
pilenum = rand(1,piles.len)
newdeck+=piles[pilenum]
piles.Cut(pilenum,pilenum+1)
TheDeck.Cut()
TheDeck.Add(newdeck)


Is now my code and compiles happily. But I believe my output is becoming different from what I expected from the code that I improved this from, because my StatPanel is giving me errors saying that it cannot create null objects whilst looking at this list.
In response to Bunnie
For some reason my code wouldn't happily work unless all lists it was trying to deal with were implicit type.
After a re-organization and re-approach I managed to get it to work. Thanks again Nadrew.

proc/PileRandom(list/TheDeck)
var
list
piles[6]
newdeck[]=new()
ii=0;
for(var/i=1;i<(piles.len+1);i++) piles[i] = new()
while(TheDeck.len>0)
ii++;
var
list
templist[]=new()
pile[]=new()
pilenum = ii%6
if(pilenum==0) pilenum=6
var/CardNum=rand(1,TheDeck.len);
templist+=TheDeck[CardNum]
pile = piles[pilenum]
templist+=pile.Copy()
pile.Cut()
pile+=templist.Copy()
TheDeck.Cut(CardNum, CardNum+1)
templist.Cut()
while(piles.len>0)
var/list/pile=new()
var/pilenum = rand(1,piles.len)
pile = piles[pilenum]
newdeck+=pile.Copy()
piles.Cut(pilenum,pilenum+1)
TheDeck.Cut()
TheDeck.Add(newdeck)
In response to Bunnie
I'm not sure why you're going through all this trouble to shuffle a deck. You don't need to mimic real-life shuffling to randomize the cards. All you need to do is:

for(var/n = 1 to L.len-1)
L.Swap(n, rand(n, L.len))
In response to Garthor
This kind of shuffle is seen as more human-realistic. Most players of Trading Card Games randomly deal cards into 6 piles.