ColorSet: turn Set into an Enum (#8757)

This commit is contained in:
Hans Mackowiak
2025-10-09 15:03:45 +02:00
committed by GitHub
parent 1962a8d28b
commit f8d883d91f
28 changed files with 138 additions and 254 deletions

View File

@@ -17,14 +17,12 @@
*/
package forge.card;
import com.google.common.collect.UnmodifiableIterator;
import forge.card.MagicColor.Color;
import forge.card.mana.ManaCost;
import forge.util.BinaryUtil;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@@ -37,90 +35,56 @@ import java.util.stream.Stream;
*
*
*/
public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Serializable {
public enum ColorSet implements Iterable<Color>, Serializable {
C(Color.COLORLESS),
W(Color.WHITE),
U(Color.BLUE),
WU(Color.WHITE, Color.BLUE),
B(Color.BLACK),
WB(Color.WHITE, Color.BLACK),
UB(Color.BLUE, Color.BLACK),
WUB(Color.WHITE, Color.BLUE, Color.BLACK),
R(Color.RED),
RW(Color.RED, Color.WHITE),
UR(Color.BLUE, Color.RED),
URW(Color.BLUE, Color.RED, Color.WHITE),
BR(Color.BLACK, Color.RED),
RWB(Color.RED, Color.WHITE, Color.BLACK),
UBR(Color.BLUE, Color.BLACK, Color.RED),
WUBR(Color.WHITE, Color.BLUE, Color.BLACK, Color.RED),
G(Color.GREEN),
GW(Color.GREEN, Color.WHITE),
GU(Color.GREEN, Color.BLUE),
GWU(Color.GREEN, Color.WHITE, Color.BLUE),
BG(Color.BLACK, Color.GREEN),
WBG(Color.WHITE, Color.BLACK, Color.GREEN),
BGU(Color.BLACK, Color.GREEN, Color.BLUE),
GWUB(Color.GREEN, Color.WHITE, Color.BLUE, Color.BLACK),
RG(Color.RED, Color.GREEN),
RGW(Color.RED, Color.GREEN, Color.WHITE),
GUR(Color.GREEN, Color.BLUE, Color.RED),
RGWU(Color.RED, Color.GREEN, Color.WHITE, Color.BLUE),
BRG(Color.BLACK, Color.RED, Color.GREEN),
BRGW(Color.BLACK, Color.RED, Color.GREEN, Color.WHITE),
UBRG(Color.BLUE, Color.BLACK, Color.RED, Color.GREEN),
WUBRG(Color.WHITE, Color.BLUE, Color.BLACK, Color.RED, Color.GREEN)
;
private static final long serialVersionUID = 794691267379929080L;
// needs to be before other static
private static final ColorSet[] cache = new ColorSet[MagicColor.ALL_COLORS + 1];
static {
byte COLORLESS = MagicColor.COLORLESS;
byte WHITE = MagicColor.WHITE;
byte BLUE = MagicColor.BLUE;
byte BLACK = MagicColor.BLACK;
byte RED = MagicColor.RED;
byte GREEN = MagicColor.GREEN;
Color C = Color.COLORLESS;
Color W = Color.WHITE;
Color U = Color.BLUE;
Color B = Color.BLACK;
Color R = Color.RED;
Color G = Color.GREEN;
//colorless
cache[COLORLESS] = new ColorSet(C);
//mono-color
cache[WHITE] = new ColorSet(W);
cache[BLUE] = new ColorSet(U);
cache[BLACK] = new ColorSet(B);
cache[RED] = new ColorSet(R);
cache[GREEN] = new ColorSet(G);
//two-color
cache[WHITE | BLUE] = new ColorSet(W, U);
cache[WHITE | BLACK] = new ColorSet(W, B);
cache[BLUE | BLACK] = new ColorSet(U, B);
cache[BLUE | RED] = new ColorSet(U, R);
cache[BLACK | RED] = new ColorSet(B, R);
cache[BLACK | GREEN] = new ColorSet(B, G);
cache[RED | GREEN] = new ColorSet(R, G);
cache[RED | WHITE] = new ColorSet(R, W);
cache[GREEN | WHITE] = new ColorSet(G, W);
cache[GREEN | BLUE] = new ColorSet(G, U);
//three-color
cache[WHITE | BLUE | BLACK] = new ColorSet(W, U, B);
cache[WHITE | BLACK | GREEN] = new ColorSet(W, B, G);
cache[BLUE | BLACK | RED] = new ColorSet(U, B, R);
cache[BLUE | RED | WHITE] = new ColorSet(U, R, W);
cache[BLACK | RED | GREEN] = new ColorSet(B, R, G);
cache[BLACK | GREEN | BLUE] = new ColorSet(B, G, U);
cache[RED | GREEN | WHITE] = new ColorSet(R, G, W);
cache[RED | WHITE | BLACK] = new ColorSet(R, W, B);
cache[GREEN | WHITE | BLUE] = new ColorSet(G, W, U);
cache[GREEN | BLUE | RED] = new ColorSet(G, U, R);
//four-color
cache[WHITE | BLUE | BLACK | RED] = new ColorSet(W, U, B, R);
cache[BLUE | BLACK | RED | GREEN] = new ColorSet(U, B, R, G);
cache[BLACK | RED | GREEN | WHITE] = new ColorSet(B, R, G, W);
cache[RED | GREEN | WHITE | BLUE] = new ColorSet(R, G, W, U);
cache[GREEN | WHITE | BLUE | BLACK] = new ColorSet(G, W, U, B);
//five-color
cache[WHITE | BLUE | BLACK | RED | GREEN] = new ColorSet(W, U, B, R, G);
}
private final Collection<Color> orderedShards;
private final byte myColor;
private final float orderWeight;
private final Set<Color> enumSet;
private final String desc;
public static final ColorSet ALL_COLORS = fromMask(MagicColor.ALL_COLORS);
public static final ColorSet NO_COLORS = fromMask(MagicColor.COLORLESS);
private ColorSet(final Color... ordered) {
this.orderedShards = Arrays.asList(ordered);
this.myColor = orderedShards.stream().map(Color::getColorMask).reduce((byte)0, (a, b) -> (byte)(a | b));
this.orderWeight = this.getOrderWeight();
this.enumSet = EnumSet.copyOf(orderedShards);
this.desc = orderedShards.stream().map(Color::getShortName).collect(Collectors.joining());
this.orderWeight = this.calcOrderWeight();
}
public static ColorSet fromMask(final int mask) {
final int mask32 = mask & MagicColor.ALL_COLORS;
return cache[mask32];
return values()[mask32];
}
public static ColorSet fromEnums(final Color... colors) {
@@ -167,7 +131,10 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
* @return true, if successful
*/
public boolean hasAnyColor(final int colormask) {
return (this.myColor & colormask) != 0;
return (this.ordinal() & colormask) != 0;
}
public boolean hasAnyColor(final Color c) {
return this.orderedShards.contains(c);
}
/**
@@ -178,12 +145,12 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
* @return true, if successful
*/
public boolean hasAllColors(final int colormask) {
return (this.myColor & colormask) == colormask;
return (this.ordinal() & colormask) == colormask;
}
/** this has exactly the colors defined by operand. */
public boolean hasExactlyColor(final int colormask) {
return this.myColor == colormask;
return this.ordinal() == colormask;
}
/** this has no other colors except defined by operand. */
@@ -193,17 +160,17 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
/** this has no other colors except defined by operand. */
public boolean hasNoColorsExcept(final int colormask) {
return (this.myColor & ~colormask) == 0;
return (this.ordinal() & ~colormask) == 0;
}
/** This returns the colors that colormask contains that are not in color */
public ColorSet getMissingColors(final byte colormask) {
return fromMask(this.myColor & ~colormask);
return fromMask(this.ordinal() & ~colormask);
}
/** Operand has no other colors except defined by this. */
public boolean containsAllColorsFrom(final int colorProfile) {
return (~this.myColor & colorProfile) == 0;
return (~this.ordinal() & colorProfile) == 0;
}
/**
@@ -212,7 +179,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
* @return the int
*/
public int countColors() {
return BinaryUtil.bitCount(this.myColor);
return BinaryUtil.bitCount(this.ordinal());
} // bit count
// order has to be: W U B R G multi colorless - same as cards numbering
@@ -222,7 +189,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
*
* @return the order weight
*/
private float getOrderWeight() {
private float calcOrderWeight() {
float res = this.countColors();
if (hasWhite()) {
res += 0.0005f;
@@ -241,6 +208,10 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
}
return res;
}
public float getOrderWeight()
{
return orderWeight;
}
/**
* Checks if is colorless.
@@ -248,7 +219,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
* @return true, if is colorless
*/
public boolean isColorless() {
return this.myColor == 0;
return this == C;
}
/**
@@ -266,7 +237,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
* @return true, if is all colors
*/
public boolean isAllColors() {
return this == ALL_COLORS;
return this == WUBRG;
}
/**
@@ -286,17 +257,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
* @return true, if is equal
*/
public boolean isEqual(final byte color) {
return color == this.myColor;
}
/*
* (non-Javadoc)
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(final ColorSet other) {
return Float.compare(this.orderWeight, other.orderWeight);
return color == this.ordinal();
}
// Presets
@@ -346,23 +307,13 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
}
public ColorSet inverse() {
byte mask = this.myColor;
byte mask = (byte)this.ordinal();
mask ^= MagicColor.ALL_COLORS;
return fromMask(mask);
}
public byte getColor() {
return myColor;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return desc;
return (byte)ordinal();
}
/**
@@ -372,7 +323,7 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
* @return true, if successful
*/
public boolean sharesColorWith(final ColorSet ccOther) {
return (this.myColor & ccOther.myColor) != 0;
return (this.ordinal() & ccOther.ordinal()) != 0;
}
public ColorSet getSharedColors(final ColorSet ccOther) {
@@ -380,50 +331,20 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
}
public ColorSet getOffColors(final ColorSet ccOther) {
return fromMask(~this.myColor & ccOther.myColor);
return fromMask(~this.ordinal() & ccOther.ordinal());
}
public Set<Color> toEnumSet() {
return EnumSet.copyOf(enumSet);
return EnumSet.copyOf(orderedShards);
}
@Override
public Iterator<Byte> iterator() {
return new ColorIterator();
}
private class ColorIterator extends UnmodifiableIterator<Byte> {
int currentBit = -1;
private int getIndexOfNextColor(){
int nextBit = currentBit + 1;
while (nextBit < MagicColor.NUMBER_OR_COLORS) {
if ((myColor & MagicColor.WUBRG[nextBit]) != 0) {
break;
}
nextBit++;
}
return nextBit;
}
@Override
public boolean hasNext() {
return getIndexOfNextColor() < MagicColor.NUMBER_OR_COLORS;
}
@Override
public Byte next() {
currentBit = getIndexOfNextColor();
if (currentBit >= MagicColor.NUMBER_OR_COLORS) {
throw new NoSuchElementException();
}
return MagicColor.WUBRG[currentBit];
}
//@Override
public Iterator<Color> iterator() {
return this.orderedShards.iterator();
}
public Stream<Color> stream() {
return this.toEnumSet().stream();
return this.orderedShards.stream();
}
//Get array of mana cost shards for color set in the proper order

View File

@@ -593,7 +593,7 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
public PaperCardFlags withMarkedColors(ColorSet markedColors) {
if(markedColors == null)
markedColors = ColorSet.NO_COLORS;
markedColors = ColorSet.C;
return new PaperCardFlags(this, markedColors, null);
}

View File

@@ -112,25 +112,19 @@ public abstract class PaperCardPredicates {
}
private static final class PredicateColor implements Predicate<PaperCard> {
private final byte operand;
private final MagicColor.Color operand;
private PredicateColor(final byte color) {
private PredicateColor(final MagicColor.Color color) {
this.operand = color;
}
@Override
public boolean test(final PaperCard card) {
for (final byte color : card.getRules().getColor()) {
if (color == operand) {
return true;
}
if (card.getRules().getColor().hasAnyColor(operand)) {
return true;
}
if (card.getRules().getType().hasType(CardType.CoreType.Land)) {
for (final byte color : card.getRules().getColorIdentity()) {
if (color == operand) {
return true;
}
}
if (card.getRules().getType().hasType(CardType.CoreType.Land) && card.getRules().getColorIdentity().hasAnyColor(operand)) {
return true;
}
return false;
}
@@ -235,11 +229,11 @@ public abstract class PaperCardPredicates {
public static final Predicate<PaperCard> IS_RARE_OR_MYTHIC = PaperCardPredicates.IS_RARE.or(PaperCardPredicates.IS_MYTHIC_RARE);
public static final Predicate<PaperCard> IS_SPECIAL = new PredicateRarity(CardRarity.Special);
public static final Predicate<PaperCard> IS_BASIC_LAND_RARITY = new PredicateRarity(CardRarity.BasicLand);
public static final Predicate<PaperCard> IS_BLACK = new PredicateColor(MagicColor.BLACK);
public static final Predicate<PaperCard> IS_BLUE = new PredicateColor(MagicColor.BLUE);
public static final Predicate<PaperCard> IS_GREEN = new PredicateColor(MagicColor.GREEN);
public static final Predicate<PaperCard> IS_RED = new PredicateColor(MagicColor.RED);
public static final Predicate<PaperCard> IS_WHITE = new PredicateColor(MagicColor.WHITE);
public static final Predicate<PaperCard> IS_BLACK = new PredicateColor(MagicColor.Color.BLACK);
public static final Predicate<PaperCard> IS_BLUE = new PredicateColor(MagicColor.Color.BLUE);
public static final Predicate<PaperCard> IS_GREEN = new PredicateColor(MagicColor.Color.GREEN);
public static final Predicate<PaperCard> IS_RED = new PredicateColor(MagicColor.Color.RED);
public static final Predicate<PaperCard> IS_WHITE = new PredicateColor(MagicColor.Color.WHITE);
public static final Predicate<PaperCard> IS_COLORLESS = paperCard -> paperCard.getRules().getColor().isColorless();
public static final Predicate<PaperCard> IS_UNREBALANCED = PaperCard::isUnRebalanced;
public static final Predicate<PaperCard> IS_REBALANCED = PaperCard::isRebalanced;