Search code examples
dartdart-async

How to manage Lists with Future in dart?


I am new at Dart; and, I created a List of playing card objects called Deck. I am trying to select a random card, then remove the card from the deck. I am getting duplicates, as it appears subsequent cards are picked before the deck is reduced. How would I handle a future chain of events that will pick 10 unique random cards from the deck?

class Card{
String face;
String suit;
String rank;
String imgSrc;
String holdImgSrc;

Card(
 this.face,
 this.suit,
 this.rank,
 this.imgSrc,
 this.holdImgSrc
 );
}
import 'dart:math' show Random;
Random indexGen = new Random();


getCard1(){
  card1 = deck[indexGen.nextInt(deck.length)];
  deck.removeWhere((item) => item == card1);
  return card1;  
}         

getCard2(){
  card2 = deck[indexGen.nextInt(deck.length)];
  deck.removeWhere((item) => item == card2);
  return card2;
}

When I try to return a Card Object as a future I get:

new Future((getCard1()))
  .then((getCard2()))
  .then((getCard3()));

type 'Card' is not a subtype of type '() => dynamic' of 'computation'.

When I try to return the deck List I get:

type 'List' is not a subtype of type '() => dynamic' of 'computation'.

Am i missing the right syntax, flaw in my logic, or do I need to handle the list differently, by maybe watching for changes?

edit to add: The futures syntax works, however, the deletes do not appear to be happening correctly. I changed the code, to the code suggested by Jim-Y below, except for preloading new Card objects from a List using the second named constructor. The amended code and printout is as follows:

fullDeck[
...
var tenC  = new Card.full(17,'10_of_clubs','c','10','10_of_clubs.png','10_of_clubs_h.png');
var tenD  = new Card.full(18,'10_of_diamonds','d','10','10_of_diamonds.png','10_of_diamonds_h.png');
var tenS  = new Card.full(19,'10_of_spades','s','10','10_of_spades.png','10_of_spades_h.png');
var tenH  = new Card.full(20,'10_of_clubs','c','10','10_of_clubs.png','10_of_clubs_h.png');
...]

Deck<Card> deck = new Deck<Card>();
  Random indexGen = new Random();

   for(var c = 0; c < 20; ++c) {
     var card = new Card(c);
     deck.add(fullDeck[c]);//List of 52 full card objects

           }

   for(var i = 0; i < 10; ++i) {
     var rnd = indexGen.nextInt(deck.size());
     print('${deck.get(rnd).face} Deck size: ${deck.size()}');           
           }

         }

4_of_clubs Deck size: 19
10_of_diamonds Deck size: 18
5_of_clubs Deck size: 17
4_of_spades Deck size: 16
5_of_spades Deck size: 15
10_of_clubs Deck size: 14
10_of_clubs Deck size: 13
3_of_spades Deck size: 12
5_of_diamonds Deck size: 11
3_of_diamonds Deck size: 10

As you can see the 10 of Clubs is printed twice. So, If the 10 was removed in pass 6, why is it still there in pass 7?


Solution

  • If you want to chain the calls this way the methods must return a future:

    Caution: I have not tested the code:

    // I don't see what type 'Card' actually is from your code
    Future<Card> getCard1(){
      return new Future(() {
        card1 = deck[indexGen.nextInt(deck.length)];
        deck.removeWhere((item) => item == card1);
        return card1;  
      });
    }  
    

    the same for getCard2()

    Future<Card> getCard2(){
      return new Future(() {
        card2 = deck[indexGen.nextInt(deck.length)];
        deck.removeWhere((item) => item == card2);
        return card2;
      });
    }
    

    you call it with

    getCard1().then((c) => getCard2()).then((c) => print(c));
    

    as getCard1 and getCard2 are essentially the same methods you could combine them to one

    List<Card> cards = [];
    
    Future<Card> getCard(int i){
      return new Future(() {
        cards[i] = deck[indexGen.nextInt(deck.length)]; // not clear what card is 
        deck.removeWhere((item) => item == card[i]);
        return card[i];  
      });
    }  
    

    .

    getCard(1).then((c) => getCard(2)).then((c) => print(c));