Как управлять списками с Future в дартс?

Я новичок в Дарте; и я создал список объектов игральных карт под названием Deck. Я пытаюсь выбрать случайную карту, а затем удалить карту из колоды. Я получаю дубликаты, так как кажется, что последующие карты выбираются до того, как колода уменьшается. Как мне справиться с будущей цепочкой событий, когда из колоды будут выбраны 10 уникальных случайных карт?

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;
}

Когда я пытаюсь вернуть объект карты в качестве будущего, я получаю:

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

тип «Карта» не является подтипом типа «() => dynamic» типа «вычисление».

Когда я пытаюсь вернуть список колод, я получаю:

тип «Список» не является подтипом типа «() => динамический» для «вычисления».

Мне не хватает правильного синтаксиса, ошибка в моей логике или мне нужно обрабатывать список по-другому, возможно, наблюдая за изменениями?

отредактируйте, чтобы добавить: синтаксис фьючерсов работает, однако удаление, похоже, происходит неправильно. Я изменил код на код, предложенный Jim-Y ниже, за исключением предварительной загрузки новых объектов Card из списка с использованием второго именованного конструктора. Измененный код и распечатка выглядят следующим образом:

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

Как видите, 10 треф печатается дважды. Итак, если число 10 было удалено на этапе 6, почему оно все еще существует на этапе 7?


person Community    schedule 26.05.2014    source источник
comment
какие переменные card1 и card2 вы используете в getCardX()   -  person Günter Zöchbauer    schedule 26.05.2014
comment
Это карточные объекты. Колода списка заполнена карточными объектами.   -  person    schedule 26.05.2014
comment
Вы вызываете getCard1 напрямую и используете возвращенный объект Card в качестве аргумента для new Future(). Для правильных типов вам нужно написать new Future(getCard1).then((_)=>getCard2()).then((_)=>getCard3()). Он по-прежнему не запоминает карты, которые были удалены.   -  person lrn    schedule 26.05.2014
comment
Ирн: Вы правы насчет запоминания карт. Они объявляются глобальными, но не обновляются. Впереди еще одна кривая обучения :)   -  person    schedule 26.05.2014


Ответы (2)


Если вы хотите связать вызовы таким образом, методы должны возвращать будущее:

Внимание: я не тестировал код:

// 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;  
  });
}  

то же самое для getCard2()

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

вы называете это с

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

поскольку getCard1 и getCard2 по сути являются одними и теми же методами, вы можете объединить их в один

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));
person Günter Zöchbauer    schedule 26.05.2014
comment
Спасибо за супер быстрый ответ и разъяснение. Добавлено объявление класса; и изменение метода избавляет меня от сообщения об ошибке! - person ; 26.05.2014
comment
карта: Карта карта1; - person ; 26.05.2014
comment
Ok. по комбинированному методу я пробовал: deck.removeWhere((item) =› item ==cards[i]); карты возврата[i]; и позвонил, как вы предложили. теперь я получаю. У нулевого объекта нет метода «тогда». - person ; 26.05.2014
comment
Не забудьте вернуть будущее из функций getCard. - person lrn; 26.05.2014
comment
Также вы можете использовать removeAt для удаления карты: cards[i] = deck.removeAt(indexGen.nextInt(deck.length));. Гораздо проще и эффективнее, чем использовать removeWhere, когда вы уже знаете индекс. - person lrn; 26.05.2014
comment
Извините, я возвращаю карточный объект, извлеченный из колоды. Либо карта1, либо карта[i]. Это то, что сейчас называют будущим? - person ; 26.05.2014
comment
Извините, я забыл добавить return, как упоминалось @lrn. Я обновил код. Это был основной момент, который я пытался продемонстрировать, а потом забыл добавить :-( - person Günter Zöchbauer; 26.05.2014
comment
Ok. Теперь я получаю свой экземпляр карты. Прохладный. - person ; 26.05.2014

Теперь я не понимаю, почему для этого нужно использовать фьючерсы. В следующем коде я попытаюсь рассмотреть, возможно, лучший подход к удалению карты из колоды с использованием общих функций Dart :)

Ваш оригинальный класс Card, я расширил его для демонстрационных целей:

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

  Card(this.id);
  Card.full(this.id, this.face, this.suit, this.rank, this.imgSrc, this.holdImgSrc);
}

Затем вы можете создать общий контейнер для своих карточек вместо использования простого списка.

class Deck<T extends Card> {
  List<T> _container = new List<T>();

  T get(int index) => _container.removeAt(index);
  void add(T item) => _container.add(item);
  int size() => _container.length;
}

Это упростит дальнейшее расширение вашего примера, и вы получите большую выразительную мощь.

Затем вы можете написать что-то вроде этого, чтобы удалить 10 случайных элементов из колоды.

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

  for(var c = 0; c < 20; ++c) {
    var card = new Card(c);
    deck.add(card);
  }

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

В этом простом примере с этими простыми карточными объектами нет дубликатов. Однако, если вам нужно, вы можете расширить свой класс Deck с помощью метода (n) fGet, который может быть методом, возвращающим Future, как упоминалось ранее @Günter.

Надеюсь, я дал вам несколько хороших идей :)

Ваше здоровье

person Jim-Y    schedule 27.05.2014
comment
прохладно. Итак, мы переходим к классу с геттером и сеттером, но я не вижу, что должно предотвратить случайное генерирование одного и того же случайного числа. Как насчет пересечения Set?var deck = new Set();//все 52 карты vardrawCards = new Set(); var myTenCards = новый набор(); var listDeck = новый список (52); в то время как (myTenCards.length ‹ 10){drawnCards.add(listDeck[indexGen.nextInt]) myTenCards = deck.intersection(drawnCards); } - person ; 27.05.2014
comment
Я согласен, что фьючерсы кажутся ненужными. И чтобы избежать получения одной и той же карты дважды, я бы сказал, что самым простым и, возможно, самым верным для домена было бы перетасовать карты, а затем взять первые 10. То есть создать случайную перестановку колоды. Для этого есть простой алгоритм (перетасовка Кнута). - person Alan Knight; 27.05.2014
comment
Алан. Для перетасовки ваше лучшее прагматичное решение. Я пытался эмулировать настоящую колоду, удаляя по одной за раз, что привело меня к вопросу, почему мой алгоритм не работает с дубликатами, поэтому вопрос был академического рода, как это сделать таким образом. Приведенный выше метод Set также создал дубликаты. Спасибо - person ; 27.05.2014
comment
T get(int index) => _container.removeAt(index); Это ключ к тому, чтобы не генерировать одни и те же числа снова и снова, но не так, как вы ожидаете. removeAt не только вернет элемент, но и удалит этот элемент из контейнера, а Dart переупорядочит (сдвинет индексы влево) элементы. Таким образом, на следующем ходу генератор rnd num создаст случайное число в диапазоне от 0 до 19). Есть много возможностей не удалять карту из списка, а просто сделать ее эксклюзивной для следующего раунда. - person Jim-Y; 27.05.2014
comment
Попался спасибо. В оригинале я предполагал, что повторяющиеся числа были выполнены для асинхронных операций, которые выполняются быстрее, чем удаления. при дальнейшем рассмотрении выясняется, что индексы не обновляются должным образом после удаления. - person ; 27.05.2014
comment
10_треф 10_бубнов 10_пиков 2_треф 2_бубнов Это исходный порядок в списке. Потом после удаления. 10_треф 10_бубнов 10_треф 10_пиков 2_треф - person ; 27.05.2014
comment
10 клубов добавляются в исходный список, а не выбираются дважды. - person ; 27.05.2014