mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
GUI: hand - added default card sorting on mulligan (lands > other > creatures; mana value, name);
This commit is contained in:
parent
525ca9a1a2
commit
10641f8d63
10 changed files with 188 additions and 35 deletions
|
|
@ -127,10 +127,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
public boolean loadCards(SimpleCardsView cardsView, BigCard bigCard, UUID gameId) {
|
||||
return loadCards(CardsViewUtil.convertSimple(cardsView), bigCard, gameId, true);
|
||||
}
|
||||
|
||||
public boolean loadCards(CardsView cardsView, BigCard bigCard, UUID gameId, boolean revertOrder) {
|
||||
boolean changed = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
package mage.client.dialog;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.InternalFrameAdapter;
|
||||
import javax.swing.event.InternalFrameEvent;
|
||||
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
||||
|
||||
import mage.cards.MageCard;
|
||||
import mage.client.cards.BigCard;
|
||||
|
|
@ -117,7 +114,7 @@ public class CardInfoWindowDialog extends MageDialog implements MageDesktopIconi
|
|||
cards.changeGUISize();
|
||||
}
|
||||
|
||||
public void loadCards(ExileView exile, BigCard bigCard, UUID gameId) {
|
||||
public void loadCardsAndShow(ExileView exile, BigCard bigCard, UUID gameId) {
|
||||
boolean changed = cards.loadCards(exile, bigCard, gameId, true);
|
||||
String titel = name + " (" + exile.size() + ')';
|
||||
setTitle(titel);
|
||||
|
|
@ -136,16 +133,8 @@ public class CardInfoWindowDialog extends MageDialog implements MageDesktopIconi
|
|||
}
|
||||
}
|
||||
|
||||
public void loadCards(SimpleCardsView showCards, BigCard bigCard, UUID gameId) {
|
||||
cards.loadCards(showCards, bigCard, gameId);
|
||||
showAndPositionWindow();
|
||||
}
|
||||
|
||||
public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId) {
|
||||
loadCards(showCards, bigCard, gameId, true);
|
||||
}
|
||||
|
||||
public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId, boolean revertOrder) {
|
||||
// TODO: remove oudated code with revertOrder (wait new release and delete if no bug reports for diff windows with cards, 2023-12-14)
|
||||
public void loadCardsAndShow(CardsView showCards, BigCard bigCard, UUID gameId, boolean revertOrder) {
|
||||
cards.loadCards(showCards, bigCard, gameId, revertOrder);
|
||||
|
||||
// additional info for grave windows
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
private static final String CMD_AUTO_ORDER_NAME_LAST = "cmdAutoOrderNameLast";
|
||||
private static final String CMD_AUTO_ORDER_RESET_ALL = "cmdAutoOrderResetAll";
|
||||
|
||||
private final Map<UUID, PlayAreaPanel> players = new HashMap<>();
|
||||
private final Map<UUID, Boolean> playersWhoLeft = new HashMap<>();
|
||||
private final Map<UUID, PlayAreaPanel> players = new LinkedHashMap<>();
|
||||
private final Map<UUID, Boolean> playersWhoLeft = new LinkedHashMap<>();
|
||||
|
||||
// non modal frames
|
||||
private final Map<UUID, CardInfoWindowDialog> exiles = new HashMap<>();
|
||||
|
|
@ -103,7 +103,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
private boolean menuNameSet = false;
|
||||
private boolean handCardsOfOpponentAvailable = false;
|
||||
|
||||
private Map<String, Card> loadedCards = new HashMap<>();
|
||||
private final Map<String, Card> loadedCards = new HashMap<>();
|
||||
|
||||
private int storedHeight;
|
||||
private Map<String, HoverButton> hoverButtons;
|
||||
|
|
@ -893,7 +893,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
if (windowDialog.isClosed()) {
|
||||
graveyardWindows.remove(player.getName());
|
||||
} else {
|
||||
windowDialog.loadCards(player.getGraveyard(), bigCard, gameId, false);
|
||||
windowDialog.loadCardsAndShow(player.getGraveyard(), bigCard, gameId, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -904,7 +904,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
if (windowDialog.isClosed()) {
|
||||
sideboardWindows.remove(player.getName());
|
||||
} else {
|
||||
windowDialog.loadCards(player.getSideboard(), bigCard, gameId, false);
|
||||
windowDialog.loadCardsAndShow(player.getSideboard(), bigCard, gameId, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -959,7 +959,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
MageFrame.getDesktop().add(exileWindow, JLayeredPane.PALETTE_LAYER);
|
||||
exileWindow.show();
|
||||
}
|
||||
exileWindow.loadCards(exile, bigCard, gameId);
|
||||
exileWindow.loadCardsAndShow(exile, bigCard, gameId);
|
||||
}
|
||||
|
||||
// update open or remove closed card hints windows
|
||||
|
|
@ -1334,7 +1334,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
graveyardWindows.put(playerName, newGraveyard);
|
||||
MageFrame.getDesktop().add(newGraveyard, JLayeredPane.PALETTE_LAYER);
|
||||
// use graveyards to sync selection (don't use player data here)
|
||||
newGraveyard.loadCards(graveyards.get(playerName), bigCard, gameId, false);
|
||||
newGraveyard.loadCardsAndShow(graveyards.get(playerName), bigCard, gameId, false);
|
||||
}
|
||||
|
||||
private void clearClosedCardHintsWindows() {
|
||||
|
|
@ -1387,7 +1387,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
sideboardWindows.put(playerView.getName(), windowDialog);
|
||||
MageFrame.getDesktop().add(windowDialog, JLayeredPane.PALETTE_LAYER);
|
||||
// use sideboards to sync selection (don't use player data here)
|
||||
windowDialog.loadCards(sideboards.get(playerView.getName()), bigCard, gameId, false);
|
||||
windowDialog.loadCardsAndShow(sideboards.get(playerView.getName()), bigCard, gameId, false);
|
||||
}
|
||||
|
||||
public void openTopLibraryWindow(String playerName) {
|
||||
|
|
@ -1448,10 +1448,10 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
case REVEAL:
|
||||
case REVEAL_TOP_LIBRARY:
|
||||
case COMPANION:
|
||||
cardInfoWindowDialog.loadCards((CardsView) cardsView, bigCard, gameId);
|
||||
cardInfoWindowDialog.loadCardsAndShow((CardsView) cardsView, bigCard, gameId, false);
|
||||
break;
|
||||
case LOOKED_AT:
|
||||
cardInfoWindowDialog.loadCards((SimpleCardsView) cardsView, bigCard, gameId);
|
||||
cardInfoWindowDialog.loadCardsAndShow(CardsViewUtil.convertSimple((SimpleCardsView) cardsView), bigCard, gameId, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public class HandPanel extends JPanel {
|
|||
}
|
||||
|
||||
public void loadCards(CardsView cards, BigCard bigCard, UUID gameId) {
|
||||
hand.loadCards(cards, bigCard, gameId, true);
|
||||
hand.loadCards(cards, bigCard, gameId, false);
|
||||
}
|
||||
|
||||
private JPanel jPanel;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
package org.mage.test.mulligan;
|
||||
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.mulligan.MulliganDefaultHandSorter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class MulliganCardSorterTest extends CardTestPlayerBase {
|
||||
|
||||
private void assertHandSort(List<String> goodList) {
|
||||
MulliganDefaultHandSorter sorter = new MulliganDefaultHandSorter();
|
||||
|
||||
// prepare good list
|
||||
List<Card> good = goodList
|
||||
.stream()
|
||||
.map(name -> currentGame.getCards()
|
||||
.stream()
|
||||
.filter(c -> c.getName().equals(name))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Can't find testing card " + name))
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// multiple tests with diff starting order
|
||||
IntStream.range(0, 5).forEach(x -> {
|
||||
List<Card> bad = new ArrayList<>(good);
|
||||
Collections.shuffle(bad);
|
||||
|
||||
CardsImpl sorted = new CardsImpl(bad);
|
||||
sorted.sortCards(currentGame, sorter);
|
||||
List<Card> badSorted = new ArrayList<>(sorted.getCards(currentGame));
|
||||
assertList(good, badSorted);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertList(List<Card> need, List<Card> sorted) {
|
||||
String needStr = need.stream().map(Card::getName).collect(Collectors.joining("; "));
|
||||
String sortedStr = sorted.stream().map(Card::getName).collect(Collectors.joining("; "));
|
||||
Assert.assertEquals("bad sorting", needStr, sortedStr);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_HandSorting() {
|
||||
// init cards for sort testing
|
||||
// lands
|
||||
addCard(Zone.HAND, playerA, "Forest", 1);
|
||||
addCard(Zone.HAND, playerA, "Mountain", 1);
|
||||
addCard(Zone.HAND, playerA, "Island", 1);
|
||||
// other
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt", 1); // mana 1, instant
|
||||
addCard(Zone.HAND, playerA, "From Beyond", 1); // mana 4, enchantment
|
||||
addCard(Zone.HAND, playerA, "Samite Blessing", 1); // mana 1, enchantment
|
||||
addCard(Zone.HAND, playerA, "Druid's Call", 1); // mana 2, enchantment
|
||||
// creatures
|
||||
addCard(Zone.HAND, playerA, "Grizzly Bears", 1); // mana 2
|
||||
addCard(Zone.HAND, playerA, "Aspiring Champion", 1); // mana 4
|
||||
addCard(Zone.HAND, playerA, "Yellow Scarves Troops", 1); // mana 2
|
||||
addCard(Zone.HAND, playerA, "Marchesa's Infiltrator", 1); // mana 3
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
// lands by name
|
||||
assertHandSort(Arrays.asList(
|
||||
"Forest",
|
||||
"Island",
|
||||
"Mountain"
|
||||
));
|
||||
|
||||
// creatures by mana
|
||||
assertHandSort(Arrays.asList(
|
||||
"Grizzly Bears", // 2
|
||||
"Yellow Scarves Troops", // 2
|
||||
"Marchesa's Infiltrator", // 3
|
||||
"Aspiring Champion" // 4
|
||||
));
|
||||
|
||||
// other by mana
|
||||
assertHandSort(Arrays.asList(
|
||||
"Lightning Bolt", // 1
|
||||
"Samite Blessing", // 1
|
||||
"Druid's Call", // 2
|
||||
"From Beyond" // 4
|
||||
));
|
||||
|
||||
// lands > others > creatures
|
||||
assertHandSort(Arrays.asList(
|
||||
"Forest", // land
|
||||
"Island", // land
|
||||
"Lightning Bolt", // other, 1
|
||||
"Samite Blessing", // other, 1
|
||||
"Druid's Call", // other, 2
|
||||
"Grizzly Bears", // creature, 2
|
||||
"Yellow Scarves Troops" // creature, 2
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -7,10 +7,7 @@ import mage.game.Game;
|
|||
import mage.util.Copyable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
public interface Cards extends Set<UUID>, Serializable, Copyable<Cards> {
|
||||
|
||||
|
|
@ -47,7 +44,7 @@ public interface Cards extends Set<UUID>, Serializable, Copyable<Cards> {
|
|||
|
||||
Set<Card> getCards(FilterCard filter, UUID playerId, Ability source, Game game);
|
||||
|
||||
String getValue(Game game);
|
||||
String getValue(Game game); // AI related code to find changes in game state
|
||||
|
||||
/**
|
||||
* Get a collection view of the unique non-null cards in this set.
|
||||
|
|
@ -82,4 +79,6 @@ public interface Cards extends Set<UUID>, Serializable, Copyable<Cards> {
|
|||
* @param game The ongoing game.
|
||||
*/
|
||||
void removeZone(Zone zone, Game game);
|
||||
|
||||
void sortCards(Game game, Comparator<? super Card> comparator);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,4 +209,20 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
|
|||
public void removeZone(Zone zone, Game game) {
|
||||
removeIf(uuid -> game.getState().getZone(uuid) == zone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sortCards(Game game, Comparator<? super Card> comparator) {
|
||||
// workaround to sort linked list - re-create it, it must be safe for game
|
||||
List<Card> newList = this
|
||||
.stream()
|
||||
.map(game::getCard)
|
||||
.filter(Objects::nonNull)
|
||||
.sorted(comparator)
|
||||
.collect(Collectors.toList());
|
||||
if (newList.size() != this.size()) {
|
||||
throw new IllegalStateException("Wrong code usage: found unknown card id in hand while sorting, game is broken");
|
||||
}
|
||||
this.clear();
|
||||
this.addAll(newList.stream().map(Card::getId).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public abstract class Mulligan implements Serializable {
|
|||
protected final int freeMulligans;
|
||||
protected final Map<UUID, Integer> usedFreeMulligans = new HashMap<>();
|
||||
|
||||
public Mulligan(int freeMulligans) {
|
||||
Mulligan(int freeMulligans) {
|
||||
this.freeMulligans = freeMulligans;
|
||||
}
|
||||
|
||||
|
|
@ -93,5 +93,8 @@ public abstract class Mulligan implements Serializable {
|
|||
|
||||
public void drawHand(int numCards, Player player, Game game){
|
||||
player.drawCards(numCards, null, game);
|
||||
|
||||
// default hand sorting
|
||||
player.getHand().sortCards(game, new MulliganDefaultHandSorter());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
package mage.game.mulligan;
|
||||
|
||||
import mage.cards.Card;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* GUI related, hand card sorting for mulligan
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class MulliganDefaultHandSorter implements Comparator<Card> {
|
||||
|
||||
@Override
|
||||
public int compare(Card c1, Card c2) {
|
||||
// groups: lands > other > creatures
|
||||
// inside group: by mana value, by name
|
||||
|
||||
// lands
|
||||
if (c1.isLand() != c2.isLand()) {
|
||||
return Boolean.compare(c2.isLand(), c1.isLand());
|
||||
}
|
||||
// creatures
|
||||
if (c1.isCreature() != c2.isCreature()) {
|
||||
return Boolean.compare(c1.isCreature(), c2.isCreature());
|
||||
}
|
||||
// by mana
|
||||
if (c1.getManaValue() != c2.getManaValue()) {
|
||||
return Integer.compare(c1.getManaValue(), c2.getManaValue());
|
||||
}
|
||||
// by name
|
||||
return c1.getName().compareTo(c2.getName());
|
||||
}
|
||||
}
|
||||
|
|
@ -66,6 +66,9 @@ public class SmoothedLondonMulligan extends LondonMulligan {
|
|||
} else { //not enough cards in library or hand, just do a normal draw instead
|
||||
player.drawCards(numCards, null, game);
|
||||
}
|
||||
|
||||
// default hand sorting
|
||||
player.getHand().sortCards(game, new MulliganDefaultHandSorter());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue