fix FCollection (#6657)

This commit is contained in:
kevlahnota
2024-12-04 21:45:05 +08:00
committed by GitHub
parent a337fd2aed
commit a0cad5fa48
5 changed files with 203 additions and 415 deletions

View File

@@ -771,6 +771,7 @@ public class AiAttackController {
int currentAttackTax = 0;
int trampleDamage = 0;
CardCollection remainingBlockers = new CardCollection(blockers);
List<Card> removedBlockers = new ArrayList<>();
for (Card attacker : CardLists.getKeyword(blockedAttackers, Keyword.TRAMPLE)) {
// TODO might sort by quotient of dmg/cost for best combination
Cost tax = CombatUtil.getAttackCost(ai.getGame(), attacker, defendingOpponent);
@@ -784,9 +785,11 @@ public class AiAttackController {
for (Card blocker : remainingBlockers) {
if (CombatUtil.canBlock(attacker, blocker) && damage > 0) {
damage -= ComputerUtilCombat.shieldDamage(attacker, blocker);
remainingBlockers.remove(blocker);
removedBlockers.add(blocker);
}
}
remainingBlockers.removeAll(removedBlockers);
removedBlockers.clear();
if (damage > 0) {
trampleDamage += damage;
}

View File

@@ -16,9 +16,9 @@ import forge.game.spellability.*;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class PlayAi extends SpellAbilityAi {
@@ -220,13 +220,9 @@ public class PlayAi extends SpellAbilityAi {
if (cards != null & sa.hasParam("ValidSA")) {
final String valid[] = sa.getParam("ValidSA").split(",");
final Iterator<Card> itr = cards.iterator();
while (itr.hasNext()) {
final Card c = itr.next();
if (!Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, ai), SpellAbilityPredicates.isValid(valid, ai , source, sa))) {
itr.remove();
}
}
final List<Card> invalid = cards.stream().filter(c -> !Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, ai), SpellAbilityPredicates.isValid(valid, ai, source, sa))).collect(Collectors.toList());
if (!invalid.isEmpty())
cards.removeAll(invalid);
}
// Ensure that if a ValidZone is specified, there's at least something to choose from in that zone.

View File

@@ -1,32 +1,30 @@
package forge.util.collect;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.Predicate;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import org.apache.commons.lang3.ArrayUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
/**
* Collection with unique elements ({@link Set}) that maintains the order in
* which the elements are added to it ({@link List}).
* <p>
*
* This object is serializable if all elements it contains are.
*
* @param <T> the type of the elements this collection contains.
@@ -34,7 +32,6 @@ import com.google.common.collect.Sets;
*/
public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>, Cloneable, Serializable {
private static final long serialVersionUID = -1664555336364294106L;
private final Object lock = new Object();
private static final FCollection<?> EMPTY = new EmptyFCollection<>();
@@ -46,12 +43,12 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
/**
* The {@link Set} representation of this collection.
*/
private final Supplier<Set<T>> set = Suppliers.memoize(Sets::newHashSet);
private final Set<T> set = Collections.synchronizedSet(new HashSet<>());
/**
* The {@link List} representation of this collection.
*/
private final Supplier<LinkedList<T>> list = Suppliers.memoize(Lists::newLinkedList);
private final List<T> list = Collections.synchronizedList(new ArrayList<>());
/**
* Create an empty {@link FCollection}.
@@ -62,7 +59,8 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
/**
* Create an {@link FCollection} containing a single element.
*
* @param e the single element the new collection contains.
* @param e
* the single element the new collection contains.
*/
public FCollection(final T e) {
add(e);
@@ -72,7 +70,8 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
* Create an {@link FCollection} from an array. The order of the elements in
* the array is preserved in the new collection.
*
* @param c an array, whose elements will be in the collection upon its
* @param c
* an array, whose elements will be in the collection upon its
* creation.
*/
public FCollection(final T[] c) {
@@ -83,7 +82,8 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
* Create an {@link FCollection} from an {@link Iterable}. The order of the
* elements in the iterable is preserved in the new collection.
*
* @param i an iterable, whose elements will be in the collection upon its
* @param i
* an iterable, whose elements will be in the collection upon its
* creation.
*/
public FCollection(final Iterable<? extends T> i) {
@@ -93,19 +93,19 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
/**
* Create an {@link FCollection} from an {@link FCollectionReader}.
*
* @param reader a reader used to populate collection
* @param reader
* a reader used to populate collection
*/
public FCollection(final FCollectionReader<T> reader) {
synchronized (lock) {
reader.readAll(this);
}
}
/**
* Check whether an {@link Iterable} contains any iterable, silently
* returning {@code false} when {@code null} is passed as an argument.
*
* @param iterable a card collection.
* @param iterable
* a card collection.
*/
public static boolean hasElements(final Iterable<?> iterable) {
return iterable != null && !Iterables.isEmpty(iterable);
@@ -115,8 +115,10 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
* Check whether a {@link Collection} contains a particular element, silently
* returning {@code false} when {@code null} is passed as the first argument.
*
* @param collection a collection.
* @param element a possible element of the collection.
* @param collection
* a collection.
* @param element
* a possible element of the collection.
*/
public static <T> boolean hasElement(final Collection<T> collection, final T element) {
return collection != null && collection.contains(element);
@@ -132,12 +134,12 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
/**
* <p>This implementation uses the hash code of the backing list.</p>
* <p>
*
* {@inheritDoc}
*/
@Override
public int hashCode() {
return list.get().hashCode();
return list.hashCode();
}
/**
@@ -147,7 +149,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public String toString() {
return list.get().toString();
return list.toString();
}
/**
@@ -156,37 +158,35 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public final FCollection<T> clone() {
synchronized (lock) {
return new FCollection<>(list.get());
}
return new FCollection<>(list);
}
/**
* Get the first object in this {@link FCollection}.
*
* @throws NoSuchElementException if the collection is empty.
* @throws NoSuchElementException
* if the collection is empty.
*/
@Override
public T getFirst() {
synchronized (lock) {
if (list.get().isEmpty())
if (list.isEmpty())
return null;
return list.get().getFirst();
}
return list.get(0);
//return list.getFirst();
}
/**
* Get the last object in this {@link FCollection}.
*
* @throws NoSuchElementException if the collection is empty.
* @throws NoSuchElementException
* if the collection is empty.
*/
@Override
public T getLast() {
synchronized (lock) {
if (list.get().isEmpty())
if (list.isEmpty())
return null;
return list.get().getLast();
}
return list.get(list.size() - 1);
//return list.getLast();
}
/**
@@ -194,9 +194,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public int size() {
synchronized (lock) {
return set.get().size();
}
return set.size();
}
/**
@@ -204,25 +202,24 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public boolean isEmpty() {
return set.get().isEmpty();
return set.isEmpty();
}
public Set<T> asSet() {
return set.get();
return set;
}
/**
* Check whether this collection contains a particular object.
*
* @param o an object.
* @param o
* an object.
*/
@Override
public boolean contains(final Object o) {
synchronized (lock) {
if (o == null)
return false;
return set.get().contains(o);
}
return set.contains(o);
}
/**
@@ -230,8 +227,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public Iterator<T> iterator() {
return new Itr();
//return list.get().iterator();
return list.iterator();
}
/**
@@ -239,9 +235,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public Object[] toArray() {
synchronized (lock) {
return list.get().toArray();
}
return list.toArray();
}
/**
@@ -250,68 +244,60 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
@Override
@SuppressWarnings("hiding")
public <T> T[] toArray(final T[] a) {
synchronized (lock) {
return list.get().toArray(a);
}
return list.toArray(a);
}
/**
* Add an element to this collection, if it isn't already present.
*
* @param e the object to add.
* @param e
* the object to add.
* @return whether the collection changed as a result of this method call.
*/
@Override
public boolean add(final T e) {
synchronized (lock) {
if (e == null)
return false;
if (set.get().add(e)) {
list.get().add(e);
if (set.add(e)) {
list.add(e);
return true;
}
return false;
}
}
/**
* Remove an element from this collection.
*
* @param o the object to remove.
* @param o
* the object to remove.
* @return whether the collection changed as a result of this method call.
*/
@Override
public boolean remove(final Object o) {
synchronized (lock) {
if (o == null)
return false;
if (set.get().remove(o)) {
list.get().remove(o);
if (set.remove(o)) {
list.remove(o);
return true;
}
return false;
}
}
@Override
public boolean removeIf(Predicate<? super T> filter) {
synchronized (lock) {
if (list.get().removeIf(filter)) {
set.get().removeIf(filter);
if (list.removeIf(filter)) {
set.removeIf(filter);
return true;
}
return false;
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean containsAll(final Collection<?> c) {
synchronized (lock) {
return set.get().containsAll(c);
}
return set.containsAll(c);
}
/**
@@ -326,12 +312,12 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
* Add all the elements in the specified {@link Iterator} to this
* collection, in the order in which they appear.
*
* @param i an iterator.
* @param i
* an iterator.
* @return whether this collection changed as a result of this method call.
* @see #addAll(Collection)
*/
public boolean addAll(final Iterable<? extends T> i) {
synchronized (lock) {
boolean changed = false;
if (i == null)
return false;
@@ -340,24 +326,22 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
}
return changed;
}
}
/**
* Add all the elements in the specified array to this collection,
* respecting the ordering.
*
* @param c an array.
* @param c
* an array.
* @return whether this collection changed as a result of this method call.
*/
public boolean addAll(final T[] c) {
synchronized (lock) {
boolean changed = false;
for (final T e : c) {
changed |= add(e);
}
return changed;
}
}
/**
* {@inheritDoc}
@@ -365,7 +349,6 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
@SuppressWarnings("unchecked")
@Override
public boolean addAll(final int index, final Collection<? extends T> c) {
synchronized (lock) {
if (c == null) {
return false;
}
@@ -383,7 +366,6 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
}
return changed;
}
}
/**
* {@inheritDoc}
@@ -396,11 +378,11 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
/**
* Remove all objects appearing in an {@link Iterable}.
*
* @param c an iterable.
* @param c
* an iterable.
* @return whether this collection changed as a result of this method call.
*/
public boolean removeAll(final Iterable<?> c) {
synchronized (lock) {
boolean changed = false;
if (c == null)
return false;
@@ -409,34 +391,27 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
}
return changed;
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean retainAll(final Collection<?> c) {
synchronized (lock) {
if (set.get().retainAll(c)) {
list.get().retainAll(c);
if (set.retainAll(c)) {
list.retainAll(c);
return true;
}
return false;
}
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
synchronized (lock) {
if (set.get().isEmpty()) {
return;
}
set.get().clear();
list.get().clear();
}
if (set.isEmpty()) { return; }
set.clear();
list.clear();
}
/**
@@ -444,9 +419,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public T get(final int index) {
synchronized (lock) {
return list.get().get(index);
}
return list.get(index);
}
/**
@@ -456,9 +429,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public T set(final int index, final T element) { //assume this isn't called except when changing list order, so don't worry about updating set
synchronized (lock) {
return list.get().set(index, element);
}
return list.set(index, element);
}
/**
@@ -472,18 +443,19 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
/**
* Helper method to insert an element at a particular index.
*
* @param index the index to insert the element at.
* @param element the element to insert.
* @param index
* the index to insert the element at.
* @param element
* the element to insert.
* @return whether this collection changed as a result of this method call.
*/
private boolean insert(int index, final T element) {
synchronized (lock) {
if (set.get().add(element)) {
list.get().add(index, element);
if (set.add(element)) {
list.add(index, element);
return true;
}
//re-position in list if needed
final int oldIndex = list.get().indexOf(element);
final int oldIndex = list.indexOf(element);
if (index == oldIndex) {
return false;
}
@@ -491,34 +463,29 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
if (index > oldIndex) {
index--; //account for being removed
}
list.get().remove(oldIndex);
list.get().add(index, element);
list.remove(oldIndex);
list.add(index, element);
return true;
}
}
/**
* {@inheritDoc}
*/
@Override
public T remove(final int index) {
synchronized (lock) {
final T removedItem = list.get().remove(index);
final T removedItem = list.remove(index);
if (removedItem != null) {
set.get().remove(removedItem);
set.remove(removedItem);
}
return removedItem;
}
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(final Object o) {
synchronized (lock) {
return list.get().indexOf(o);
}
return list.indexOf(o);
}
/**
@@ -526,9 +493,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public int lastIndexOf(final Object o) {
synchronized (lock) {
return list.get().lastIndexOf(o);
}
return list.lastIndexOf(o);
}
/**
@@ -536,8 +501,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public ListIterator<T> listIterator() {
return new ListItr(0);
//return list.get().listIterator();
return list.listIterator();
}
/**
@@ -545,8 +509,7 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
@Override
public ListIterator<T> listIterator(final int index) {
return new ListItr(index);
//return list.get().listIterator(index);
return list.listIterator(index);
}
/**
@@ -554,14 +517,12 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
* <b>Note</b> This method breaks the contract of {@link List#subList(int, int)}
* by returning a static collection, rather than a view, of the sublist.
* </p>
* <p>
*
* {@inheritDoc}
*/
@Override
public List<T> subList(final int fromIndex, final int toIndex) {
synchronized (lock) {
return ImmutableList.copyOf(list.get().subList(fromIndex, toIndex));
}
return ImmutableList.copyOf(list.subList(fromIndex, toIndex));
}
/**
@@ -580,18 +541,15 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
* {@inheritDoc}
*/
public void sort(final Comparator<? super T> comparator) {
synchronized (lock) {
try {
list.get().sort(comparator);
list.sort(comparator);
} catch (Exception e) {
System.err.println("FCollection failed to sort: \n" + comparator + "\n" + e.getMessage());
}
}
}
@Override
public T get(final T obj) {
synchronized (lock) {
if (obj == null) {
return null;
}
@@ -602,8 +560,6 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
}
return obj;
}
}
/**
* An unmodifiable, empty {@link FCollection}. Overrides all methods with
* default implementations suitable for an empty collection, to improve
@@ -611,155 +567,93 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
*/
public static class EmptyFCollection<T> extends FCollection<T> {
private static final long serialVersionUID = 8667965158891635997L;
public EmptyFCollection() {
super();
}
@Override
public final void add(final int index, final T element) {
@Override public final void add(final int index, final T element) {
}
@Override
public final boolean add(final T e) {
@Override public final boolean add(final T e) {
return false;
}
@Override
public final boolean addAll(final Collection<? extends T> c) {
@Override public final boolean addAll(final Collection<? extends T> c) {
return false;
}
@Override
public final boolean addAll(final int index, final Collection<? extends T> c) {
@Override public final boolean addAll(final int index, final Collection<? extends T> c) {
return false;
}
@Override
public final boolean addAll(final Iterable<? extends T> i) {
@Override public final boolean addAll(final Iterable<? extends T> i) {
return false;
}
@Override
public final boolean addAll(final T[] c) {
@Override public final boolean addAll(final T[] c) {
return false;
}
@Override
public final void clear() {
@Override public final void clear() {
}
@Override
public final boolean contains(final Object o) {
@Override public final boolean contains(final Object o) {
return false;
}
@Override
public final boolean containsAll(final Collection<?> c) {
@Override public final boolean containsAll(final Collection<?> c) {
return c.isEmpty();
}
@Override
public final T get(final int index) {
@Override public final T get(final int index) {
throw new IndexOutOfBoundsException("Any index is out of bounds for an empty collection");
}
@Override
public final T getFirst() {
@Override public final T getFirst() {
throw new NoSuchElementException("Collection is empty");
}
@Override
public final T getLast() {
@Override public final T getLast() {
throw new NoSuchElementException("Collection is empty");
}
@Override
public final int indexOf(final Object o) {
@Override public final int indexOf(final Object o) {
return -1;
}
@Override
public final boolean isEmpty() {
@Override public final boolean isEmpty() {
return true;
}
@Override
public final Iterator<T> iterator() {
@Override public final Iterator<T> iterator() {
return Collections.emptyIterator();
}
@Override
public final int lastIndexOf(final Object o) {
@Override public final int lastIndexOf(final Object o) {
return -1;
}
@Override
public final ListIterator<T> listIterator() {
@Override public final ListIterator<T> listIterator() {
return Collections.emptyListIterator();
}
@Override
public final ListIterator<T> listIterator(final int index) {
@Override public final ListIterator<T> listIterator(final int index) {
return Collections.emptyListIterator();
}
@Override
public final T remove(final int index) {
@Override public final T remove(final int index) {
throw new IndexOutOfBoundsException("Any index is out of bounds for an empty collection");
}
@Override
public final boolean remove(final Object o) {
@Override public final boolean remove(final Object o) {
return false;
}
@Override
public boolean removeAll(final Collection<?> c) {
@Override public boolean removeAll(final Collection<?> c) {
return false;
}
@Override
public final boolean removeAll(final Iterable<?> c) {
@Override public final boolean removeAll(final Iterable<?> c) {
return false;
}
@Override
public final boolean retainAll(final Collection<?> c) {
@Override public final boolean retainAll(final Collection<?> c) {
return false;
}
@Override
public final T set(final int index, final T element) {
@Override public final T set(final int index, final T element) {
throw new IndexOutOfBoundsException("Any index is out of bounds for an empty collection");
}
@Override
public final int size() {
@Override public final int size() {
return 0;
}
@Override
public final void sort() {
@Override public final void sort() {
}
@Override
public final void sort(final Comparator<? super T> comparator) {
@Override public final void sort(final Comparator<? super T> comparator) {
}
@Override
public final List<T> subList(final int fromIndex, final int toIndex) {
@Override public final List<T> subList(final int fromIndex, final int toIndex) {
if (fromIndex == 0 && toIndex == 0) {
return this;
}
throw new IndexOutOfBoundsException("Any index is out of bounds for an empty collection");
}
@Override
public final Object[] toArray() {
return ArrayUtils.EMPTY_OBJECT_ARRAY;
}
@Override public final Object[] toArray() { return ArrayUtils.EMPTY_OBJECT_ARRAY; }
@Override
@SuppressWarnings("hiding")
public final <T> T[] toArray(final T[] a) {
@@ -768,101 +662,8 @@ public class FCollection<T> implements List<T>, /*Set<T>,*/ FCollectionView<T>,
}
return a;
}
@Override
public final String toString() {
@Override public final String toString() {
return "[]";
}
}
private class Itr implements Iterator<T> {
protected int cursor;
protected int lastRet;
final FCollection l;
public Itr() {
cursor = 0;
lastRet = -1;
l = FCollection.this.clone();
}
@Override
public boolean hasNext() {
return cursor < l.size();
}
@Override
public T next() {
int i = cursor;
if (i >= l.size()) {
throw new NoSuchElementException();
}
cursor = i + 1;
return (T) l.get(lastRet = i);
}
@Override
public void remove() {
if (lastRet < 0) {
throw new IllegalStateException();
}
l.remove(lastRet);
FCollection.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
}
}
public class ListItr extends Itr implements ListIterator<T> {
ListItr(int index) {
super();
cursor = index;
}
@Override
public boolean hasPrevious() {
return cursor > 0;
}
@Override
public int nextIndex() {
return cursor;
}
@Override
public int previousIndex() {
return cursor - 1;
}
@Override
public T previous() {
int i = cursor - 1;
if (i < 0) {
throw new NoSuchElementException();
}
cursor = i;
return (T) l.get(lastRet = i);
}
@Override
public void set(T e) {
if (lastRet < 0) {
throw new IllegalStateException();
}
l.set(lastRet, e);
FCollection.this.set(lastRet, e);
}
@Override
public void add(T e) {
int i = cursor;
l.add(i, e);
FCollection.this.add(i, e);
cursor = i + 1;
lastRet = -1;
}
}
}

View File

@@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import forge.card.CardStateName;
import forge.card.GamePieceType;
@@ -192,15 +193,9 @@ public class PlayEffect extends SpellAbilityEffect {
if (sa.hasParam("ValidSA")) {
final String valid[] = sa.getParam("ValidSA").split(",");
Iterator<Card> it = tgtCards.iterator();
while (it.hasNext()) {
Card c = it.next();
if (!Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, controller), SpellAbilityPredicates.isValid(valid, controller , source, sa))) {
// it.remove will only remove item from the list part of CardCollection
tgtCards.asSet().remove(c);
it.remove();
}
}
final List<Card> invalid = tgtCards.stream().filter(c -> !Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, controller), SpellAbilityPredicates.isValid(valid, controller, source, sa))).collect(Collectors.toList());
if (!invalid.isEmpty())
tgtCards.removeAll(invalid);
if (tgtCards.isEmpty()) {
return;
}
@@ -233,16 +228,10 @@ public class PlayEffect extends SpellAbilityEffect {
while (!tgtCards.isEmpty() && amount > 0 && totalCMCLimit >= 0) {
if (hasTotalCMCLimit) {
// filter out cards with mana value greater than limit
Iterator<Card> it = tgtCards.iterator();
final String [] valid = {"Spell.cmcLE" + totalCMCLimit};
while (it.hasNext()) {
Card c = it.next();
if (!Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, controller), SpellAbilityPredicates.isValid(valid, controller , c, sa))) {
// it.remove will only remove item from the list part of CardCollection
tgtCards.asSet().remove(c);
it.remove();
}
}
final List<Card> invalid = tgtCards.stream().filter(c -> !Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, controller), SpellAbilityPredicates.isValid(valid, controller, c, sa))).collect(Collectors.toList());
if (!invalid.isEmpty())
tgtCards.removeAll(invalid);
if (tgtCards.isEmpty())
break;
params.put("CMCLimit", totalCMCLimit);

View File

@@ -5,7 +5,6 @@ import forge.game.card.CardCollection;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -15,7 +14,7 @@ public class FCollectionTest {
/**
* Just a quick test for FCollection.
*/
@Test
/*@Test
void testBadIteratorLogic() {
List<Card> cards = new ArrayList<>();
for (int i = 1; i < 5; i++)
@@ -27,7 +26,7 @@ public class FCollectionTest {
assertEquals(cc.size(), 3);
}
@Test
/*@Test
void testBadIteratorLogicTwo() {
List<Card> cards = new ArrayList<>();
for (int i = 1; i <= 10; i++)
@@ -40,7 +39,7 @@ public class FCollectionTest {
i++;
}
assertEquals(cc.size(), 1);
}
}*/// Commented out since we use synchronized collection and it doesn't support modification while iteration
@Test
void testCompletableFuture() {