From 379f31847bcc3d8d1114b256d8943804de44fedf Mon Sep 17 00:00:00 2001 From: Alyssa Date: Wed, 3 Dec 2025 22:03:02 +0000 Subject: [PATCH 1/5] wip revamp strategy API --- client/src/main/java/object/ApiStrategy.java | 93 ----- .../src/main/java/screen/ApiAmendDialog.java | 227 ------------ .../main/java/screen/SimulationDialog.java | 17 +- client/src/main/java/util/ApiUtil.java | 342 +++++------------- client/src/main/java/util/CpuStrategies.java | 24 +- .../src/main/kotlin/screen/ApiAmendDialog.kt | 158 ++++++++ .../screen/preference/PreferencesDialog.kt | 2 - .../preference/PreferencesPanelPlayers.kt | 55 +-- .../src/main/kotlin/strategy/ApiStrategy.kt | 10 + client/src/main/kotlin/strategy/ApiUtil.kt | 52 +++ 10 files changed, 368 insertions(+), 612 deletions(-) delete mode 100644 client/src/main/java/object/ApiStrategy.java delete mode 100644 client/src/main/java/screen/ApiAmendDialog.java create mode 100644 client/src/main/kotlin/screen/ApiAmendDialog.kt create mode 100644 client/src/main/kotlin/strategy/ApiStrategy.kt create mode 100644 client/src/main/kotlin/strategy/ApiUtil.kt diff --git a/client/src/main/java/object/ApiStrategy.java b/client/src/main/java/object/ApiStrategy.java deleted file mode 100644 index 301c9d33..00000000 --- a/client/src/main/java/object/ApiStrategy.java +++ /dev/null @@ -1,93 +0,0 @@ -package object; - -/** - * Wrapper class for an API strategy - */ -public class ApiStrategy -{ - private String name = ""; - private boolean entropy = false; - private boolean vectropy = false; - private int portNumber = -1; - private String messageType = ""; - private String error = ""; - - public Object[] getTableModelRow() - { - boolean enabled = error.isEmpty(); - Object[] row = {name, Integer.valueOf(portNumber), getGameModeDesc(), messageType, Boolean.valueOf(enabled)}; - return row; - } - - public boolean isEnabled() - { - return error.isEmpty(); - } - - private String getGameModeDesc() - { - if (entropy - && vectropy) - { - return "Both"; - } - else if (entropy) - { - return "Entropy"; - } - - return "Vectropy"; - } - - /** - * Gets / sets - */ - public String getName() - { - return name; - } - public void setName(String name) - { - this.name = name; - } - public boolean getEntropy() - { - return entropy; - } - public void setEntropy(boolean entropy) - { - this.entropy = entropy; - } - public boolean getVectropy() - { - return vectropy; - } - public void setVectropy(boolean vectropy) - { - this.vectropy = vectropy; - } - public int getPortNumber() - { - return portNumber; - } - public void setPortNumber(int portNumber) - { - this.portNumber = portNumber; - } - public String getMessageType() - { - return messageType; - } - public void setMessageType(String messageType) - { - this.messageType = messageType; - } - public String getError() - { - return error; - } - public void setError(String error) - { - this.error = error; - } -} diff --git a/client/src/main/java/screen/ApiAmendDialog.java b/client/src/main/java/screen/ApiAmendDialog.java deleted file mode 100644 index ffee025f..00000000 --- a/client/src/main/java/screen/ApiAmendDialog.java +++ /dev/null @@ -1,227 +0,0 @@ -package screen; - -import java.awt.BorderLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.JTextField; - -import object.ApiStrategy; -import util.ApiUtil; -import util.DialogUtil; - -public class ApiAmendDialog extends JDialog - implements ActionListener -{ - private static final int DEFAULT_PORT_NUMBER = 1153; - - private ApiStrategy strategy = null; - - - public ApiAmendDialog() - { - setTitle("API Setup"); - setSize(350, 300); - setLocationRelativeTo(null); - setResizable(false); - setModal(true); - - getContentPane().add(okCancelPanel, BorderLayout.SOUTH); - okCancelPanel.add(btnOk); - okCancelPanel.add(btnCancel); - getContentPane().add(panel, BorderLayout.CENTER); - panel.setLayout(null); - lblName.setBounds(10, 10, 100, 25); - panel.add(lblName); - lblGameMode.setBounds(10, 45, 100, 25); - panel.add(lblGameMode); - rdbtnEntropy.setBounds(110, 45, 80, 25); - panel.add(rdbtnEntropy); - rdbtnVectropy.setBounds(190, 45, 80, 25); - panel.add(rdbtnVectropy); - rdbtnBoth.setBounds(270, 45, 80, 25); - panel.add(rdbtnBoth); - btnGroupMode.add(rdbtnEntropy); - btnGroupMode.add(rdbtnVectropy); - btnGroupMode.add(rdbtnBoth); - textFieldName.setBounds(110, 10, 120, 25); - panel.add(textFieldName); - textFieldName.setColumns(10); - lblPort.setBounds(10, 80, 100, 25); - panel.add(lblPort); - textFieldPort.setBounds(110, 80, 80, 25); - panel.add(textFieldPort); - textFieldPort.setColumns(10); - lblMessageType.setBounds(10, 115, 100, 25); - panel.add(lblMessageType); - rdbtnXml.setBounds(110, 116, 80, 23); - panel.add(rdbtnXml); - rdbtnJson.setBounds(190, 116, 109, 23); - panel.add(rdbtnJson); - btnGroupMessageType.add(rdbtnXml); - btnGroupMessageType.add(rdbtnJson); - btnTest.setBounds(120, 172, 89, 23); - panel.add(btnTest); - - btnOk.addActionListener(this); - btnCancel.addActionListener(this); - btnTest.addActionListener(this); - } - - private final JPanel okCancelPanel = new JPanel(); - private final JButton btnOk = new JButton("Ok"); - private final JButton btnCancel = new JButton("Cancel"); - private final JPanel panel = new JPanel(); - private final JLabel lblName = new JLabel("Name"); - private final JTextField textFieldName = new JTextField(); - private final JLabel lblGameMode = new JLabel("Game Mode"); - private final JRadioButton rdbtnEntropy = new JRadioButton("Entropy"); - private final JRadioButton rdbtnVectropy = new JRadioButton("Vectropy"); - private final JRadioButton rdbtnBoth = new JRadioButton("Both"); - private final ButtonGroup btnGroupMode = new ButtonGroup(); - private final JLabel lblPort = new JLabel("Port"); - private final JTextField textFieldPort = new JTextField(); - private final JLabel lblMessageType = new JLabel("Messaging"); - private final JRadioButton rdbtnXml = new JRadioButton(ApiUtil.MESSAGE_TYPE_XML); - private final JRadioButton rdbtnJson = new JRadioButton(ApiUtil.MESSAGE_TYPE_JSON); - private final ButtonGroup btnGroupMessageType = new ButtonGroup(); - private final JButton btnTest = new JButton("Test"); - - public void init(ApiStrategy strategy) - { - this.strategy = strategy; - - if (strategy == null) - { - //Clear fields - textFieldName.setText(""); - textFieldPort.setText("" + DEFAULT_PORT_NUMBER); - rdbtnEntropy.setSelected(true); - rdbtnXml.setSelected(true); - } - else - { - //Populate fields - textFieldName.setText(strategy.getName()); - textFieldPort.setText("" + strategy.getPortNumber()); - - boolean entropy = strategy.getEntropy(); - boolean vectropy = strategy.getVectropy(); - - rdbtnEntropy.setSelected(entropy); - rdbtnVectropy.setSelected(vectropy); - rdbtnBoth.setSelected(entropy && vectropy); - - String messageType = strategy.getMessageType(); - rdbtnXml.setSelected(messageType.equals(ApiUtil.MESSAGE_TYPE_XML)); - rdbtnJson.setSelected(messageType.equals(ApiUtil.MESSAGE_TYPE_JSON)); - } - - //rdbtnJson.setEnabled(false); - } - - @Override - public void actionPerformed(ActionEvent arg0) - { - JButton source = (JButton)arg0.getSource(); - if (source == btnOk) - { - if (valid()) - { - saveData(); - } - } - else if (source == btnCancel) - { - dispose(); - } - else if (source == btnTest) - { - sendTestMessage(); - } - } - - private boolean valid() - { - String name = textFieldName.getText(); - if (name.isEmpty()) - { - DialogUtil.showError("You must enter a name for this setup."); - return false; - } - - return true; - } - - private void saveData() - { - if (strategy == null) - { - strategy = new ApiStrategy(); - } - - String name = textFieldName.getText(); - strategy.setName(name); - - String portStr = textFieldPort.getText(); - int port = Integer.parseInt(portStr); - strategy.setPortNumber(port); - - boolean entropy = rdbtnEntropy.isSelected() || rdbtnBoth.isSelected(); - boolean vectropy = rdbtnVectropy.isSelected() || rdbtnBoth.isSelected(); - - strategy.setEntropy(entropy); - strategy.setVectropy(vectropy); - - if (rdbtnXml.isSelected()) - { - strategy.setMessageType(ApiUtil.MESSAGE_TYPE_XML); - } - else - { - strategy.setMessageType(ApiUtil.MESSAGE_TYPE_JSON); - } - - dispose(); - } - - private void sendTestMessage() - { - String infoMsg = "About to send a test message on port " + textFieldPort.getText() - + "\n\nEnsure that the third-party software is running and listening on this port."; - - DialogUtil.showInfo(infoMsg); - - String portStr = textFieldPort.getText(); - int port = Integer.parseInt(portStr); - - ApiUtil.sendTestMessage(port, rdbtnXml.isSelected()); - } - - public ApiStrategy getApiStrategy() - { - return strategy; - } - - public static ApiStrategy createStrategy() - { - ApiAmendDialog dialog = new ApiAmendDialog(); - dialog.init(null); - dialog.setVisible(true); - - return dialog.getApiStrategy(); - } - - public static void amendStrategy(ApiStrategy strategy) - { - ApiAmendDialog dialog = new ApiAmendDialog(); - dialog.init(strategy); - dialog.setVisible(true); - } -} diff --git a/client/src/main/java/screen/SimulationDialog.java b/client/src/main/java/screen/SimulationDialog.java index 37e41252..dc1084cc 100644 --- a/client/src/main/java/screen/SimulationDialog.java +++ b/client/src/main/java/screen/SimulationDialog.java @@ -515,7 +515,7 @@ public void actionPerformed(ActionEvent arg0) private void updateStrategySelection() { - Vector allStrategies = CpuStrategies.getAllStrategies(rdbtnEntropy.isSelected(), null); + Vector allStrategies = CpuStrategies.getAllStrategies(getSelectedGameMode(), null); ComboBoxModel comboModel = new DefaultComboBoxModel<>(allStrategies); opponentZeroStrat.setModel(comboModel); @@ -526,14 +526,19 @@ private void updateStrategySelection() comboModel = new DefaultComboBoxModel<>(allStrategies); opponentThreeStrat.setModel(comboModel); } - - private SimulationParams factorySimulationParms() - { - GameMode gameMode = GameMode.Entropy; + + private GameMode getSelectedGameMode() { if (rdbtnVectropy.isSelected()) { - gameMode = GameMode.Vectropy; + return GameMode.Vectropy; } + + return GameMode.Entropy; + } + + private SimulationParams factorySimulationParms() + { + GameMode gameMode = getSelectedGameMode(); int numberOfCards = slider.getValue(); boolean includeJokers = cbIncludeJokers.isSelected(); diff --git a/client/src/main/java/util/ApiUtil.java b/client/src/main/java/util/ApiUtil.java index 10234324..50caee32 100644 --- a/client/src/main/java/util/ApiUtil.java +++ b/client/src/main/java/util/ApiUtil.java @@ -1,15 +1,10 @@ package util; -import game.BidAction; -import game.GameMode; import game.PlayerAction; -import object.ApiStrategy; import object.Player; import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import preference.PreferenceSetting; -import settings.Setting; +import strategy.ApiStrategy; +import strategy.ApiUtilKt; import utils.CoreGlobals; import javax.swing.*; @@ -20,27 +15,12 @@ import java.net.Socket; import java.net.SocketException; import java.net.SocketTimeoutException; -import java.util.*; - -import static preference.PreferenceSettingKt.getPreference; -import static util.ClientGlobals.preferenceStore; +import java.util.HashMap; public class ApiUtil { public static final String API_PREFIX = "API: "; - public static final String MESSAGE_TYPE_XML = "XML"; - public static final String MESSAGE_TYPE_JSON = "JSON"; - - private static final String ROOT_TAG_API_MESSAGE = "ApiMessage"; private static final InetAddress INET_ADDRESS_LOCALHOST = MessageUtil.factoryInetAddress("localhost"); - - private static final String PREFERENCES_TAG_API = "Api"; - private static final String PREFERENCES_ATTR_API_NAME = "ApiName"; - private static final String PREFERENCES_ATTR_PORT_NUMNER = "PortNumber"; - private static final String PREFERENCES_ATTR_MESSAGE_TYPE = "MessageType"; - private static final String PREFERENCES_ATTR_SUPPORTS_ENTROPY = "Entropy"; - private static final String PREFERENCES_ATTR_SUPPORTS_VECTROPY = "Vectropy"; - private static final String PREFERENCES_ATTR_ERROR = "Error"; //Cache this for speed in the simulator private static HashMap hmNameToApiStrategy = null; @@ -62,10 +42,9 @@ public static void sendTestMessage(int port, boolean xml) public static PlayerAction processApiTurn(StrategyParams parms, Player player) { apiStrategy = getApiStrategy(player.getStrategy()); - int port = apiStrategy.getPortNumber(); - String messageType = apiStrategy.getMessageType(); + int port = apiStrategy.getPort(); - String messageString = factoryApiMessage(parms, player, messageType); + String messageString = "some message TODO"; String responseString = sendWithCatch(messageString, port, parms.getLogging(), false); if (responseString == null) @@ -109,7 +88,7 @@ private static String sendWithCatch(String messageString, int port, boolean logg } else if (!testMode) { - saveStrategyErrorAndUnsetStrategies(apiStrategy, "An error occurred connecting to the third party software."); + ApiUtilKt.saveStrategyErrorAndUnsetStrategies(apiStrategy, "An error occurred connecting to the third party software."); } } catch (Throwable t) @@ -124,7 +103,7 @@ else if (!testMode) DialogUtilNew.showError("A severe error occurred communicating with the third party software. " + "\n\nLogs have been sent for investigation."); - saveStrategyErrorAndUnsetStrategies(apiStrategy, "A severe error occurred communicating with the third party software."); + ApiUtilKt.saveStrategyErrorAndUnsetStrategies(apiStrategy, "A severe error occurred communicating with the third party software."); } finally { @@ -137,104 +116,83 @@ else if (!testMode) return responseString; } - private static String factoryApiMessage(StrategyParams parms, Player player, String messageType) - { - if (messageType.equals(MESSAGE_TYPE_XML)) - { - return factoryXmlApiMessage(parms, player); - } - - return factoryJsonApiMessage(parms, player); - } - - private static String factoryXmlApiMessage(StrategyParams parms, Player player) - { - Document document = XmlUtil.factoryNewDocument(); - Element rootElement = document.createElement(ROOT_TAG_API_MESSAGE); - - var settings = parms.getSettings(); - GameMode gameMode = settings.getMode(); - int totalCards = parms.getCardsInPlay(); - int jokerQuantity = settings.getJokerQuantity(); - int jokerValue = settings.getJokerValue(); - boolean includeMoons = settings.getIncludeMoons(); - boolean includeStars = settings.getIncludeStars(); - boolean negativeJacks = settings.getNegativeJacks(); - boolean cardReveal = settings.getCardReveal(); - BidAction lastBid = parms.getLastBid(); - - rootElement.setAttribute("GameMode", gameMode.name()); - - List playerHand = player.getHand(); - Element handElement = document.createElement("PlayerHand"); - int length = playerHand.size(); - for (int i=0; i 0) - { - rootElement.setAttribute("JokerQuantity", "" + jokerQuantity); - rootElement.setAttribute("JokerValue", "" + jokerValue); - } - - XmlUtil.setAttributeBoolean(rootElement, "IncludeMoons", includeMoons); - XmlUtil.setAttributeBoolean(rootElement, "IncludeStars", includeStars); - XmlUtil.setAttributeBoolean(rootElement, "NegativeJacks", negativeJacks); - XmlUtil.setAttributeBoolean(rootElement, "ShowCards", cardReveal); - - if (cardReveal) - { - Element opponentCardsOnShow = document.createElement("OpponentCardsOnShow"); - List cards = parms.getOpponentCardsOnShow(); - for (int i=0; i 0) - { - rootElement.appendChild(opponentCardsOnShow); - } - - Element myCardsAlreadyShowing = document.createElement("PlayerCardsOnShow"); - cards = player.getRevealedCards(); - for (int i=0; i 0) - { - rootElement.appendChild(myCardsAlreadyShowing); - } - } - - if (lastBid != null) - { - rootElement.setAttribute("LastBid", lastBid.toJsonString()); - } - - document.appendChild(rootElement); - return XmlUtil.getStringFromDocument(document); - } - - private static String factoryJsonApiMessage(StrategyParams parms, Player player) - { - if (parms == null - || player == null) - { - //Empty if block to avoid warnings - } - - return null; - } +// private static String factoryXmlApiMessage(StrategyParams parms, Player player) +// { +// Document document = XmlUtil.factoryNewDocument(); +// Element rootElement = document.createElement(ROOT_TAG_API_MESSAGE); +// +// var settings = parms.getSettings(); +// GameMode gameMode = settings.getMode(); +// int totalCards = parms.getCardsInPlay(); +// int jokerQuantity = settings.getJokerQuantity(); +// int jokerValue = settings.getJokerValue(); +// boolean includeMoons = settings.getIncludeMoons(); +// boolean includeStars = settings.getIncludeStars(); +// boolean negativeJacks = settings.getNegativeJacks(); +// boolean cardReveal = settings.getCardReveal(); +// BidAction lastBid = parms.getLastBid(); +// +// rootElement.setAttribute("GameMode", gameMode.name()); +// +// List playerHand = player.getHand(); +// Element handElement = document.createElement("PlayerHand"); +// int length = playerHand.size(); +// for (int i=0; i 0) +// { +// rootElement.setAttribute("JokerQuantity", "" + jokerQuantity); +// rootElement.setAttribute("JokerValue", "" + jokerValue); +// } +// +// XmlUtil.setAttributeBoolean(rootElement, "IncludeMoons", includeMoons); +// XmlUtil.setAttributeBoolean(rootElement, "IncludeStars", includeStars); +// XmlUtil.setAttributeBoolean(rootElement, "NegativeJacks", negativeJacks); +// XmlUtil.setAttributeBoolean(rootElement, "ShowCards", cardReveal); +// +// if (cardReveal) +// { +// Element opponentCardsOnShow = document.createElement("OpponentCardsOnShow"); +// List cards = parms.getOpponentCardsOnShow(); +// for (int i=0; i 0) +// { +// rootElement.appendChild(opponentCardsOnShow); +// } +// +// Element myCardsAlreadyShowing = document.createElement("PlayerCardsOnShow"); +// cards = player.getRevealedCards(); +// for (int i=0; i 0) +// { +// rootElement.appendChild(myCardsAlreadyShowing); +// } +// } +// +// if (lastBid != null) +// { +// rootElement.setAttribute("LastBid", lastBid.toJsonString()); +// } +// +// document.appendChild(rootElement); +// return XmlUtil.getStringFromDocument(document); +// } private static PlayerAction handleResponse(String responseString) { @@ -251,7 +209,7 @@ private static void showMalformedResponseError(String response) String message = "The third-party software returned an unexpected message type:" + "\n\n" + response; - saveStrategyErrorAndUnsetStrategies(apiStrategy, message); + ApiUtilKt.saveStrategyErrorAndUnsetStrategies(apiStrategy, message); message += "\n\nRefer to the API documentation to see the responses that are accepted."; DialogUtilNew.showError(message); @@ -259,64 +217,12 @@ private static void showMalformedResponseError(String response) private static void initialiseStrategyHashMap() { - HashMap temp = new HashMap<>(); - - String apiStrategies = getPreference(PreferenceSetting.ApiStrategies); - if (apiStrategies.isBlank()) { - return; - } + hmNameToApiStrategy = new HashMap<>(); - Document apiXml = XmlUtil.getDocumentFromXmlString(apiStrategies); - if (apiXml == null) - { - hmNameToApiStrategy = temp; - return; - } - - Element rootElement = apiXml.getDocumentElement(); - NodeList strategyTags = rootElement.getElementsByTagName(PREFERENCES_TAG_API); - int size = strategyTags.getLength(); - for (int i=0; i getApiStrategiesFromPreferences() - { - ArrayList strategies = new ArrayList<>(); - if (hmNameToApiStrategy == null) - { - initialiseStrategyHashMap(); - } - - Iterator> it = hmNameToApiStrategy.entrySet().iterator(); - for (; it.hasNext(); ) - { - Map.Entry entry = it.next(); - ApiStrategy strategy = entry.getValue(); - strategies.add(strategy); - } - - return strategies; } public static ApiStrategy getApiStrategy(String name) @@ -325,79 +231,11 @@ public static ApiStrategy getApiStrategy(String name) { initialiseStrategyHashMap(); } - + int prefixLength = API_PREFIX.length(); int totalLength = name.length(); name = name.substring(prefixLength, totalLength); return hmNameToApiStrategy.get(name); } - - public static void saveApiStrategiesToPreferences(List strategies) - { - //Construct a document with any old root element - Document apiDoc = XmlUtil.factoryNewDocument(); - Element rootElement = apiDoc.createElement("ApiStrategies"); - - int size = strategies.size(); - for (int i=0; i apiStrategies = getApiStrategiesFromPreferences(); - for (int i=0; i strategySetting, String apiName) - { - String strategy = getPreference(strategySetting); - if (strategy.equals("API: " + apiName)) - { - preferenceStore.save(strategySetting, CpuStrategies.STRATEGY_BASIC); - } - } } diff --git a/client/src/main/java/util/CpuStrategies.java b/client/src/main/java/util/CpuStrategies.java index ae030c4f..2af13be3 100644 --- a/client/src/main/java/util/CpuStrategies.java +++ b/client/src/main/java/util/CpuStrategies.java @@ -2,6 +2,8 @@ import game.*; import object.*; +import strategy.ApiStrategy; +import strategy.ApiUtilKt; import java.util.ArrayList; import java.util.List; @@ -15,31 +17,31 @@ public class CpuStrategies public static final String STRATEGY_BASIC = "Easy"; public static final String STRATEGY_EV = "Hard"; - public static Vector getAllStrategies(boolean entropy, List apiStrategies) + public static Vector getAllStrategies(GameMode gameMode, List apiStrategies) { - Vector allStrategies = getFixedStrategies(entropy); + Vector allStrategies = getFixedStrategies(gameMode); //Append the relevant API strategies if (apiStrategies == null) { - apiStrategies = ApiUtil.getApiStrategiesFromPreferences(); + apiStrategies = ApiUtilKt.getApiStrategiesFromPreferences(); } - appendRelevantStrategies(allStrategies, apiStrategies, entropy); + appendRelevantStrategies(allStrategies, apiStrategies, gameMode); return allStrategies; } private static void appendRelevantStrategies(Vector allStrategies, - List apiStrategies, boolean entropy) + List apiStrategies, GameMode gameMode) { int size = apiStrategies.size(); for (int i=0; i allStrategies, } } - private static Vector getFixedStrategies(boolean entropy) + private static Vector getFixedStrategies(GameMode gameMode) { - if (entropy) + if (gameMode == GameMode.Entropy) { return EntCpuStrategies.getAllStrategies(); } @@ -84,7 +86,7 @@ public static PlayerAction processOpponentTurn(StrategyParams parms, Player oppo + "failed validation with the following error:\n\n" + error; String strategyStr = opponent.getStrategy(); - ApiUtil.saveStrategyErrorAndUnsetStrategies(ApiUtil.getApiStrategy(strategyStr), msg); + ApiUtilKt.saveStrategyErrorAndUnsetStrategies(ApiUtil.getApiStrategy(strategyStr), msg); DialogUtilNew.showError(msg); } else diff --git a/client/src/main/kotlin/screen/ApiAmendDialog.kt b/client/src/main/kotlin/screen/ApiAmendDialog.kt new file mode 100644 index 00000000..56813f14 --- /dev/null +++ b/client/src/main/kotlin/screen/ApiAmendDialog.kt @@ -0,0 +1,158 @@ +package screen + +import game.GameMode +import java.awt.BorderLayout +import java.awt.event.ActionEvent +import java.awt.event.ActionListener +import javax.swing.JButton +import javax.swing.JCheckBox +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.JTextField +import strategy.ApiStrategy +import util.ApiUtil +import util.DialogUtilNew + +class ApiAmendDialog : SimpleDialog(), ActionListener { + private var apiStrategy: ApiStrategy? = null + + private val okCancelPanel = JPanel() + private val panel = JPanel() + private val lblName = JLabel("Name") + private val textFieldName = JTextField() + private val lblGameMode = JLabel("Game Mode") + private val rdbtnEntropy = JCheckBox("Entropy") + private val rdbtnVectropy = JCheckBox("Vectropy") + private val lblPort = JLabel("Port") + private val textFieldPort = JTextField() + private val lblMessageType = JLabel("Messaging") + private val btnTest = JButton("Test") + + private val modeMappings = + listOf(rdbtnEntropy to GameMode.Entropy, rdbtnVectropy to GameMode.Vectropy) + + init { + title = "API Setup" + setSize(350, 300) + setLocationRelativeTo(null) + isResizable = false + isModal = true + + contentPane.add(okCancelPanel, BorderLayout.SOUTH) + okCancelPanel.add(btnOk) + okCancelPanel.add(btnCancel) + contentPane.add(panel, BorderLayout.CENTER) + panel.layout = null + lblName.setBounds(10, 10, 100, 25) + panel.add(lblName) + lblGameMode.setBounds(10, 45, 100, 25) + panel.add(lblGameMode) + rdbtnEntropy.setBounds(110, 45, 80, 25) + panel.add(rdbtnEntropy) + rdbtnVectropy.setBounds(190, 45, 80, 25) + panel.add(rdbtnVectropy) + textFieldName.setBounds(110, 10, 120, 25) + panel.add(textFieldName) + textFieldName.columns = 10 + lblPort.setBounds(10, 80, 100, 25) + panel.add(lblPort) + textFieldPort.setBounds(110, 80, 80, 25) + panel.add(textFieldPort) + textFieldPort.columns = 10 + lblMessageType.setBounds(10, 115, 100, 25) + panel.add(lblMessageType) + btnTest.setBounds(120, 172, 89, 23) + panel.add(btnTest) + + btnTest.addActionListener(this) + } + + fun init(strategy: ApiStrategy?) { + this.apiStrategy = strategy + + if (strategy == null) { + textFieldName.text = "" + textFieldPort.text = "" + DEFAULT_PORT_NUMBER + rdbtnEntropy.isSelected = true + } else { + textFieldName.text = strategy.name + textFieldPort.text = "" + strategy.port + + rdbtnEntropy.isSelected = strategy.supportedModes.contains(GameMode.Entropy) + rdbtnVectropy.isSelected = strategy.supportedModes.contains(GameMode.Vectropy) + } + } + + override fun okPressed() { + if (valid()) { + saveData() + } + } + + override fun actionPerformed(arg0: ActionEvent) { + if (arg0.source === btnTest) { + sendTestMessage() + } else { + super.actionPerformed(arg0) + } + } + + private fun valid(): Boolean { + val name = textFieldName.text + if (name.isEmpty()) { + DialogUtilNew.showError("You must enter a name for this setup.") + return false + } + + if (!rdbtnEntropy.isSelected && !rdbtnVectropy.isSelected) { + DialogUtilNew.showError("You must select at least one game mode.", this) + return false + } + + return true + } + + private fun saveData() { + val supportedModes = modeMappings.filter { it.first.isSelected }.map { it.second } + apiStrategy = ApiStrategy(textFieldName.text, supportedModes, textFieldPort.text.toInt()) + + dispose() + } + + private fun sendTestMessage() { + val infoMsg = + """ + About to send a test message on port ${textFieldPort.text} + + Ensure that the third-party software is running and listening on this port. + """ + .trimIndent() + + DialogUtilNew.showInfo(infoMsg) + + val portStr = textFieldPort.text + val port = portStr.toInt() + + ApiUtil.sendTestMessage(port, true) + } + + companion object { + private const val DEFAULT_PORT_NUMBER = 1153 + + fun createStrategy(): ApiStrategy? { + val dialog = ApiAmendDialog() + dialog.init(null) + dialog.isVisible = true + + return dialog.apiStrategy + } + + fun amendStrategy(strategy: ApiStrategy): ApiStrategy? { + val dialog = ApiAmendDialog() + dialog.init(strategy) + dialog.isVisible = true + + return dialog.apiStrategy + } + } +} diff --git a/client/src/main/kotlin/screen/preference/PreferencesDialog.kt b/client/src/main/kotlin/screen/preference/PreferencesDialog.kt index 27c1f029..9c79d7fd 100644 --- a/client/src/main/kotlin/screen/preference/PreferencesDialog.kt +++ b/client/src/main/kotlin/screen/preference/PreferencesDialog.kt @@ -8,7 +8,6 @@ import javax.swing.JScrollPane import javax.swing.JTabbedPane import javax.swing.SwingConstants import screen.SimpleDialog -import util.ApiUtil import utils.getAllChildComponentsForType class PreferencesDialog : SimpleDialog() { @@ -68,7 +67,6 @@ class PreferencesDialog : SimpleDialog() { } private fun closeDialog() { - ApiUtil.clearCache() dispose() } } diff --git a/client/src/main/kotlin/screen/preference/PreferencesPanelPlayers.kt b/client/src/main/kotlin/screen/preference/PreferencesPanelPlayers.kt index 138e7119..4a9e3c4f 100644 --- a/client/src/main/kotlin/screen/preference/PreferencesPanelPlayers.kt +++ b/client/src/main/kotlin/screen/preference/PreferencesPanelPlayers.kt @@ -25,17 +25,18 @@ import javax.swing.SwingConstants import javax.swing.SwingUtilities import javax.swing.table.TableModel import javax.swing.table.TableRowSorter -import `object`.ApiStrategy import `object`.LimitedDocument import preference.PreferenceSetting import preference.getPreference import screen.ApiAmendDialog -import util.ApiUtil +import strategy.ApiStrategy +import strategy.getApiStrategiesFromPreferences import util.ClientGlobals.preferenceStore import util.CpuStrategies import util.DialogUtilNew import util.TableUtil.DefaultModel import util.TableUtil.SimpleRenderer +import utils.CoreGlobals class PreferencesPanelPlayers(parent: PreferencesDialog) : AbstractPreferencesPanel(parent), MouseListener, ItemListener { @@ -186,7 +187,10 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : preferenceStore.save(PreferenceSetting.OpponentTwoStrategy, opponentTwoStrategy) preferenceStore.save(PreferenceSetting.OpponentThreeStrategy, opponentThreeStrategy) - ApiUtil.saveApiStrategiesToPreferences(apiStrategies) + preferenceStore.save( + PreferenceSetting.ApiStrategies, + CoreGlobals.jsonMapper.writeValueAsString(apiStrategies), + ) } private fun getVariablesFromPrefs() { @@ -199,7 +203,8 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : opponentOneStrategy = getPreference(PreferenceSetting.OpponentOneStrategy) opponentTwoStrategy = getPreference(PreferenceSetting.OpponentTwoStrategy) opponentThreeStrategy = getPreference(PreferenceSetting.OpponentThreeStrategy) - apiStrategies = ApiUtil.getApiStrategiesFromPreferences() + + apiStrategies = getApiStrategiesFromPreferences() gameMode = GameMode.valueOf(getPreference(PreferenceSetting.GameMode)) } @@ -237,12 +242,11 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : model.addColumn("Name") model.addColumn("Port") model.addColumn("Game") - model.addColumn("Messaging") model.addColumn("Enabled") // Centre rendering for everything but the last column for (i in 0.. { + return listOf(name, port, supportedModes.joinToString(), lastError == null) + } + fun updateStrategySelection(gameMode: GameMode) { this.gameMode = gameMode - val allStrategies = - CpuStrategies.getAllStrategies(gameMode == GameMode.Entropy, apiStrategies) + val allStrategies = CpuStrategies.getAllStrategies(gameMode, apiStrategies) var comboModel: ComboBoxModel = DefaultComboBoxModel(allStrategies) opponentOneStrat.setModel(comboModel) @@ -271,23 +278,29 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : private fun enableApi(strategy: ApiStrategy) { val question = - "Strategy ${strategy.name} was disabled due to the following error:\n\n${strategy.error}\n\nWould you like to re-enable it?" + "Strategy ${strategy.name} was disabled due to the following error:\n\n${strategy.lastError}\n\nWould you like to re-enable it?" val option = DialogUtilNew.showQuestion(question, false) if (option == JOptionPane.YES_OPTION) { - strategy.error = "" - buildApiTable() + strategyUpdated(strategy, strategy.copy(lastError = null)) } } - private fun amendApi(strategy: ApiStrategy?) { - ApiAmendDialog.amendStrategy(strategy) + private fun amendApi(strategy: ApiStrategy) { + val newStrategy = ApiAmendDialog.amendStrategy(strategy) ?: return + + strategyUpdated(strategy, newStrategy) + } + + private fun strategyUpdated(oldStrategy: ApiStrategy, newStrategy: ApiStrategy) { + apiStrategies = apiStrategies.map { if (it == oldStrategy) newStrategy else it } + buildApiTable() } private fun deleteApi(strategy: ApiStrategy) { - val question = "Are you sure you want to delete the " + strategy.getName() + " strategy?" - val option = DialogUtilNew.showQuestion(question, false) + val question = "Are you sure you want to delete the " + strategy.name + " strategy?" + val option = DialogUtilNew.showQuestion(question, false, this) if (option == JOptionPane.YES_OPTION) { apiStrategies = apiStrategies - strategy buildApiTable() @@ -338,15 +351,15 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : } if (strategy != null) { - enableItem.setEnabled(!strategy.isEnabled) + enableItem.setEnabled(strategy.lastError != null) // Show the popup menu - popupMenu.show(arg0.component, arg0.getX(), arg0.getY()) + popupMenu.show(arg0.component, arg0.x, arg0.y) } - } else if (arg0.getClickCount() == 2) { + } else if (arg0.clickCount == 2) { // Double-click if (strategy != null) { - if (!strategy.isEnabled) { + if (strategy.lastError != null) { enableApi(strategy) } else { amendApi(strategy) @@ -362,7 +375,7 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : override fun mouseReleased(arg0: MouseEvent?) {} override fun itemStateChanged(arg0: ItemEvent) { - val source = arg0.getSource() + val source = arg0.source if (source === cbOpponentTwo) { opponentTwoEnabled = cbOpponentTwo.isSelected setOpponentEnablementAndStrategies() diff --git a/client/src/main/kotlin/strategy/ApiStrategy.kt b/client/src/main/kotlin/strategy/ApiStrategy.kt new file mode 100644 index 00000000..c05b7c01 --- /dev/null +++ b/client/src/main/kotlin/strategy/ApiStrategy.kt @@ -0,0 +1,10 @@ +package strategy + +import game.GameMode + +data class ApiStrategy( + val name: String, + val supportedModes: List, + val port: Int, + val lastError: String? = null, +) diff --git a/client/src/main/kotlin/strategy/ApiUtil.kt b/client/src/main/kotlin/strategy/ApiUtil.kt new file mode 100644 index 00000000..d39c8b31 --- /dev/null +++ b/client/src/main/kotlin/strategy/ApiUtil.kt @@ -0,0 +1,52 @@ +package strategy + +import com.fasterxml.jackson.module.kotlin.readValue +import preference.PreferenceSetting +import preference.getPreference +import settings.Setting +import util.ClientGlobals.preferenceStore +import util.CpuStrategies +import utils.CoreGlobals + +fun getApiStrategiesFromPreferences(): List { + val apiStrategyJson = getPreference(PreferenceSetting.ApiStrategies) + if (apiStrategyJson.isEmpty()) { + return emptyList() + } + + return CoreGlobals.jsonMapper.readValue>(apiStrategyJson) +} + +fun saveApiStrategiesToPreference(strategies: List) { + preferenceStore.save( + PreferenceSetting.ApiStrategies, + CoreGlobals.jsonMapper.writeValueAsString(strategies), + ) +} + +fun saveStrategyErrorAndUnsetStrategies(strategy: ApiStrategy, error: String?) { + // Something has gone wrong, so save the API strategy as disabled + val name = strategy.name + val apiStrategies = getApiStrategiesFromPreferences() + val updated = + apiStrategies.map { prefStrategy -> + if (strategy.name == prefStrategy.name) { + prefStrategy.copy(lastError = error) + } else { + prefStrategy + } + } + + saveApiStrategiesToPreference(updated) + + resetCpuStrategy(PreferenceSetting.OpponentOneStrategy, name) + resetCpuStrategy(PreferenceSetting.OpponentTwoStrategy, name) + resetCpuStrategy(PreferenceSetting.OpponentThreeStrategy, name) +} + +private fun resetCpuStrategy(strategySetting: Setting, apiName: String) { + val strategy = getPreference(strategySetting) + if (strategy == "API: $apiName") { + preferenceStore.save(strategySetting, CpuStrategies.STRATEGY_BASIC) + } +} From 3fdef9a31149350df9ade93a4338a6ad028420f7 Mon Sep 17 00:00:00 2001 From: alyssa Date: Thu, 4 Dec 2025 08:55:51 +0000 Subject: [PATCH 2/5] more WIP, oof --- .../src/main/java/object/Player.java | 11 ++-- client/src/main/java/screen/GameScreen.java | 2 +- .../main/java/screen/SimulationDialog.java | 3 +- client/src/main/java/util/ApiUtil.java | 40 ++++++------ client/src/main/java/util/CpuStrategies.java | 18 +++--- .../src/main/java/util/EntCpuStrategies.java | 3 +- .../src/main/java/util/VectCpuStrategies.java | 3 +- client/src/main/kotlin/game/StrategyUtil.kt | 2 +- .../preference/PreferencesPanelPlayers.kt | 26 ++++---- .../src/main/kotlin/strategy/ApiStrategy.kt | 6 +- client/src/main/kotlin/strategy/ApiUtil.kt | 52 ---------------- client/src/main/kotlin/strategy/IStrategy.kt | 17 ++++++ .../main/kotlin/strategy/InBuiltStrategy.kt | 3 + .../{util => strategy}/StrategyParams.kt | 2 +- .../src/main/kotlin/strategy/StrategyUtil.kt | 61 +++++++++++++++++++ client/src/main/kotlin/util/GameSimulator.kt | 1 + .../src/main/kotlin/util/SimulationParams.kt | 9 +-- .../src/main/kotlin/util/SimulationResults.kt | 5 +- client/src/test/kotlin/TestUtils.kt | 2 +- 19 files changed, 155 insertions(+), 111 deletions(-) rename {core => client}/src/main/java/object/Player.java (94%) delete mode 100644 client/src/main/kotlin/strategy/ApiUtil.kt create mode 100644 client/src/main/kotlin/strategy/IStrategy.kt create mode 100644 client/src/main/kotlin/strategy/InBuiltStrategy.kt rename client/src/main/kotlin/{util => strategy}/StrategyParams.kt (93%) create mode 100644 client/src/main/kotlin/strategy/StrategyUtil.kt diff --git a/core/src/main/java/object/Player.java b/client/src/main/java/object/Player.java similarity index 94% rename from core/src/main/java/object/Player.java rename to client/src/main/java/object/Player.java index 39856b69..773e69de 100644 --- a/core/src/main/java/object/Player.java +++ b/client/src/main/java/object/Player.java @@ -1,5 +1,8 @@ package object; +import strategy.ApiStrategy; +import strategy.IStrategy; + import java.util.ArrayList; import java.util.List; import java.util.prefs.Preferences; @@ -13,7 +16,7 @@ public class Player private int numberOfCards = -1; private int cardsToSubtract = 0; private boolean enabled = false; - private String strategy = null; + private IStrategy strategy = null; private List hand = null; private ArrayList revealedCards = new ArrayList<>(); @@ -136,7 +139,7 @@ public void setRevealedCards(ArrayList revealedCards) public boolean isApiStrategy() { - return strategy.startsWith("API"); + return strategy instanceof ApiStrategy; } public String getName() @@ -171,11 +174,11 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } - public String getStrategy() + public IStrategy getStrategy() { return strategy; } - public void setStrategy(String strategy) + public void setStrategy(IStrategy strategy) { this.strategy = strategy; } diff --git a/client/src/main/java/screen/GameScreen.java b/client/src/main/java/screen/GameScreen.java index a4d724da..772b7961 100644 --- a/client/src/main/java/screen/GameScreen.java +++ b/client/src/main/java/screen/GameScreen.java @@ -5,6 +5,7 @@ import game.*; import object.Player; import preference.PreferenceSetting; +import strategy.StrategyParams; import util.*; import javax.swing.*; @@ -20,7 +21,6 @@ import static preference.PreferenceSettingKt.getPreference; import static screen.ScreenCacheKt.IN_GAME_REPLAY; import static util.ClientGlobals.achievementStore; -import static util.ClientGlobals.preferenceStore; import static utils.CoreGlobals.logger; public abstract class GameScreen> extends TransparentPanel diff --git a/client/src/main/java/screen/SimulationDialog.java b/client/src/main/java/screen/SimulationDialog.java index dc1084cc..08235c13 100644 --- a/client/src/main/java/screen/SimulationDialog.java +++ b/client/src/main/java/screen/SimulationDialog.java @@ -3,6 +3,7 @@ import bean.NumberField; import game.GameMode; import game.GameSettings; +import strategy.IStrategy; import util.*; import javax.swing.*; @@ -374,7 +375,7 @@ public String getToolTipText(MouseEvent e) { resultsTable.setFillsViewportHeight(true); } - private void addRowIfApplicable(Vector> resultsData, String strategy, int opponentNumber) + private void addRowIfApplicable(Vector> resultsData, IStrategy strategy, int opponentNumber) { SimulationResults results = hmSimulationResultsByOpponentNumber.get(opponentNumber); if (results != null) diff --git a/client/src/main/java/util/ApiUtil.java b/client/src/main/java/util/ApiUtil.java index 50caee32..524a4477 100644 --- a/client/src/main/java/util/ApiUtil.java +++ b/client/src/main/java/util/ApiUtil.java @@ -4,7 +4,8 @@ import object.Player; import org.w3c.dom.Document; import strategy.ApiStrategy; -import strategy.ApiUtilKt; +import strategy.StrategyParams; +import strategy.StrategyUtilKt; import utils.CoreGlobals; import javax.swing.*; @@ -16,6 +17,7 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.util.HashMap; +import java.util.UUID; public class ApiUtil { @@ -24,7 +26,6 @@ public class ApiUtil //Cache this for speed in the simulator private static HashMap hmNameToApiStrategy = null; - private static ApiStrategy apiStrategy = null; public static void sendTestMessage(int port, boolean xml) { @@ -36,27 +37,26 @@ public static void sendTestMessage(int port, boolean xml) Document xmlDoc = XmlUtil.factorySimpleMessage("ApiTest"); String messageString = XmlUtil.getStringFromDocument(xmlDoc); - sendWithCatch(messageString, port, true, true); + sendWithCatch(messageString, port, true, null); } - public static PlayerAction processApiTurn(StrategyParams parms, Player player) + public static PlayerAction processApiTurn(StrategyParams parms, ApiStrategy strategy) { - apiStrategy = getApiStrategy(player.getStrategy()); - int port = apiStrategy.getPort(); + int port = strategy.getPort(); String messageString = "some message TODO"; - String responseString = sendWithCatch(messageString, port, parms.getLogging(), false); + String responseString = sendWithCatch(messageString, port, parms.getLogging(), strategy.getId()); if (responseString == null) { //An error occurred which we'll already have caught. return null; } - return handleResponse(responseString); + return handleResponse(responseString, strategy.getId()); } - private static String sendWithCatch(String messageString, int port, boolean logging, boolean testMode) + private static String sendWithCatch(String messageString, int port, boolean logging, UUID id) { Debug.append("API OUT: " + messageString, logging); @@ -84,11 +84,11 @@ private static String sendWithCatch(String messageString, int port, boolean logg int option = DialogUtilNew.showQuestion(question, false); if (option == JOptionPane.YES_OPTION) { - sendWithCatch(messageString, port, logging, testMode); + sendWithCatch(messageString, port, logging, id); } - else if (!testMode) + else if (id != null) { - ApiUtilKt.saveStrategyErrorAndUnsetStrategies(apiStrategy, "An error occurred connecting to the third party software."); + StrategyUtilKt.saveStrategyErrorAndUnsetStrategies(id, "An error occurred connecting to the third party software."); } } catch (Throwable t) @@ -102,8 +102,10 @@ else if (!testMode) Debug.stackTrace(t); DialogUtilNew.showError("A severe error occurred communicating with the third party software. " + "\n\nLogs have been sent for investigation."); - - ApiUtilKt.saveStrategyErrorAndUnsetStrategies(apiStrategy, "A severe error occurred communicating with the third party software."); + + if (id != null) { + StrategyUtilKt.saveStrategyErrorAndUnsetStrategies(id, "A severe error occurred communicating with the third party software."); + } } finally { @@ -194,22 +196,22 @@ else if (!testMode) // return XmlUtil.getStringFromDocument(document); // } - private static PlayerAction handleResponse(String responseString) + private static PlayerAction handleResponse(String responseString, UUID id) { try { return CoreGlobals.jsonMapper.readValue(responseString, PlayerAction.class); } catch (Exception e) { - showMalformedResponseError(responseString); + showMalformedResponseError(responseString, id); return null; } } - private static void showMalformedResponseError(String response) + private static void showMalformedResponseError(String response, UUID id) { String message = "The third-party software returned an unexpected message type:" + "\n\n" + response; - ApiUtilKt.saveStrategyErrorAndUnsetStrategies(apiStrategy, message); + StrategyUtilKt.saveStrategyErrorAndUnsetStrategies(id, message); message += "\n\nRefer to the API documentation to see the responses that are accepted."; DialogUtilNew.showError(message); @@ -219,7 +221,7 @@ private static void initialiseStrategyHashMap() { hmNameToApiStrategy = new HashMap<>(); - var strategies = ApiUtilKt.getApiStrategiesFromPreferences(); + var strategies = StrategyUtilKt.getApiStrategiesFromPreferences(); for (ApiStrategy strategy : strategies) { hmNameToApiStrategy.put(strategy.getName(), strategy); } diff --git a/client/src/main/java/util/CpuStrategies.java b/client/src/main/java/util/CpuStrategies.java index 2af13be3..776e3e22 100644 --- a/client/src/main/java/util/CpuStrategies.java +++ b/client/src/main/java/util/CpuStrategies.java @@ -3,7 +3,8 @@ import game.*; import object.*; import strategy.ApiStrategy; -import strategy.ApiUtilKt; +import strategy.StrategyParams; +import strategy.StrategyUtilKt; import java.util.ArrayList; import java.util.List; @@ -24,7 +25,7 @@ public static Vector getAllStrategies(GameMode gameMode, List getAllStrategies() public static PlayerAction processOpponentTurn(Player opponent, StrategyParams parms) { - String strategy = opponent.getStrategy(); + String strategy = opponent.getStrategy().getName(); return processOpponentTurn(strategy, opponent, parms); } private static PlayerAction processOpponentTurn(String strategy, Player opponent, StrategyParams parms) diff --git a/client/src/main/java/util/VectCpuStrategies.java b/client/src/main/java/util/VectCpuStrategies.java index 933d522e..6e3134e0 100644 --- a/client/src/main/java/util/VectCpuStrategies.java +++ b/client/src/main/java/util/VectCpuStrategies.java @@ -7,6 +7,7 @@ import game.Suit; import game.VectropyBidAction; import object.Player; +import strategy.StrategyParams; import static game.StrategyUtilKt.*; import static utils.CoreGlobals.logger; @@ -29,7 +30,7 @@ public static Vector getAllStrategies() public static PlayerAction processOpponentTurn(Player opponent, StrategyParams parms) { - String strategy = opponent.getStrategy(); + String strategy = opponent.getStrategy().getName(); return processOpponentTurn(strategy, opponent, parms); } private static PlayerAction processOpponentTurn(String strategy, Player opponent, StrategyParams parms) diff --git a/client/src/main/kotlin/game/StrategyUtil.kt b/client/src/main/kotlin/game/StrategyUtil.kt index f081e3bd..ba9eb82f 100644 --- a/client/src/main/kotlin/game/StrategyUtil.kt +++ b/client/src/main/kotlin/game/StrategyUtil.kt @@ -4,7 +4,7 @@ import kotlin.math.ceil import kotlin.math.floor import strategy.DefaultRandom import strategy.IRandom -import util.StrategyParams +import strategy.StrategyParams fun getEvMap( visibleCards: List, diff --git a/client/src/main/kotlin/screen/preference/PreferencesPanelPlayers.kt b/client/src/main/kotlin/screen/preference/PreferencesPanelPlayers.kt index 4a9e3c4f..eda3f34d 100644 --- a/client/src/main/kotlin/screen/preference/PreferencesPanelPlayers.kt +++ b/client/src/main/kotlin/screen/preference/PreferencesPanelPlayers.kt @@ -1,5 +1,6 @@ package screen.preference +import bean.ComboBoxItem import game.GameMode import java.awt.Font import java.awt.event.ActionEvent @@ -7,7 +8,6 @@ import java.awt.event.ItemEvent import java.awt.event.ItemListener import java.awt.event.MouseEvent import java.awt.event.MouseListener -import javax.swing.ComboBoxModel import javax.swing.DefaultComboBoxModel import javax.swing.JButton import javax.swing.JCheckBox @@ -30,9 +30,10 @@ import preference.PreferenceSetting import preference.getPreference import screen.ApiAmendDialog import strategy.ApiStrategy +import strategy.IStrategy +import strategy.getAllStrategies import strategy.getApiStrategiesFromPreferences import util.ClientGlobals.preferenceStore -import util.CpuStrategies import util.DialogUtilNew import util.TableUtil.DefaultModel import util.TableUtil.SimpleRenderer @@ -61,9 +62,9 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : private val opponentThreeNameField = JTextField() private val cbOpponentTwo = JCheckBox() private val cbOpponentThree = JCheckBox() - private val opponentOneStrat = JComboBox() - private val opponentTwoStrat = JComboBox() - private val opponentThreeStrat = JComboBox() + private val opponentOneStrat = JComboBox>() + private val opponentTwoStrat = JComboBox>() + private val opponentThreeStrat = JComboBox>() private val label = JLabel("Note: Changes will not take effect until you start a new game.") private val separator_4 = JSeparator() private val lblApiHeader = JLabel("API Options") @@ -144,7 +145,6 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : cbOpponentThree.addItemListener(this) } - /** Abstract methods */ override fun initVariables() { getVariablesFromPrefs() @@ -266,14 +266,14 @@ class PreferencesPanelPlayers(parent: PreferencesDialog) : fun updateStrategySelection(gameMode: GameMode) { this.gameMode = gameMode - val allStrategies = CpuStrategies.getAllStrategies(gameMode, apiStrategies) + val allStrategies = + getAllStrategies(gameMode, apiStrategies) + .map { strategy -> ComboBoxItem(strategy, strategy.name, true) } + .toTypedArray() - var comboModel: ComboBoxModel = DefaultComboBoxModel(allStrategies) - opponentOneStrat.setModel(comboModel) - comboModel = DefaultComboBoxModel(allStrategies) - opponentTwoStrat.setModel(comboModel) - comboModel = DefaultComboBoxModel(allStrategies) - opponentThreeStrat.setModel(comboModel) + opponentOneStrat.setModel(DefaultComboBoxModel(allStrategies)) + opponentTwoStrat.setModel(DefaultComboBoxModel(allStrategies)) + opponentThreeStrat.setModel(DefaultComboBoxModel(allStrategies)) } private fun enableApi(strategy: ApiStrategy) { diff --git a/client/src/main/kotlin/strategy/ApiStrategy.kt b/client/src/main/kotlin/strategy/ApiStrategy.kt index c05b7c01..53754ecb 100644 --- a/client/src/main/kotlin/strategy/ApiStrategy.kt +++ b/client/src/main/kotlin/strategy/ApiStrategy.kt @@ -1,10 +1,12 @@ package strategy import game.GameMode +import java.util.UUID data class ApiStrategy( - val name: String, + override val name: String, val supportedModes: List, val port: Int, val lastError: String? = null, -) + val id: UUID = UUID.randomUUID(), +) : IStrategy diff --git a/client/src/main/kotlin/strategy/ApiUtil.kt b/client/src/main/kotlin/strategy/ApiUtil.kt deleted file mode 100644 index d39c8b31..00000000 --- a/client/src/main/kotlin/strategy/ApiUtil.kt +++ /dev/null @@ -1,52 +0,0 @@ -package strategy - -import com.fasterxml.jackson.module.kotlin.readValue -import preference.PreferenceSetting -import preference.getPreference -import settings.Setting -import util.ClientGlobals.preferenceStore -import util.CpuStrategies -import utils.CoreGlobals - -fun getApiStrategiesFromPreferences(): List { - val apiStrategyJson = getPreference(PreferenceSetting.ApiStrategies) - if (apiStrategyJson.isEmpty()) { - return emptyList() - } - - return CoreGlobals.jsonMapper.readValue>(apiStrategyJson) -} - -fun saveApiStrategiesToPreference(strategies: List) { - preferenceStore.save( - PreferenceSetting.ApiStrategies, - CoreGlobals.jsonMapper.writeValueAsString(strategies), - ) -} - -fun saveStrategyErrorAndUnsetStrategies(strategy: ApiStrategy, error: String?) { - // Something has gone wrong, so save the API strategy as disabled - val name = strategy.name - val apiStrategies = getApiStrategiesFromPreferences() - val updated = - apiStrategies.map { prefStrategy -> - if (strategy.name == prefStrategy.name) { - prefStrategy.copy(lastError = error) - } else { - prefStrategy - } - } - - saveApiStrategiesToPreference(updated) - - resetCpuStrategy(PreferenceSetting.OpponentOneStrategy, name) - resetCpuStrategy(PreferenceSetting.OpponentTwoStrategy, name) - resetCpuStrategy(PreferenceSetting.OpponentThreeStrategy, name) -} - -private fun resetCpuStrategy(strategySetting: Setting, apiName: String) { - val strategy = getPreference(strategySetting) - if (strategy == "API: $apiName") { - preferenceStore.save(strategySetting, CpuStrategies.STRATEGY_BASIC) - } -} diff --git a/client/src/main/kotlin/strategy/IStrategy.kt b/client/src/main/kotlin/strategy/IStrategy.kt new file mode 100644 index 00000000..36dd6b0e --- /dev/null +++ b/client/src/main/kotlin/strategy/IStrategy.kt @@ -0,0 +1,17 @@ +package strategy + +import com.fasterxml.jackson.annotation.JsonSubTypes +import com.fasterxml.jackson.annotation.JsonTypeInfo + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "strategyType", +) +@JsonSubTypes( + JsonSubTypes.Type(value = InBuiltStrategy::class, name = "IN_BUILT"), + JsonSubTypes.Type(value = ApiStrategy::class, name = "API"), +) +interface IStrategy { + val name: String +} diff --git a/client/src/main/kotlin/strategy/InBuiltStrategy.kt b/client/src/main/kotlin/strategy/InBuiltStrategy.kt new file mode 100644 index 00000000..3349c627 --- /dev/null +++ b/client/src/main/kotlin/strategy/InBuiltStrategy.kt @@ -0,0 +1,3 @@ +package strategy + +data class InBuiltStrategy(override val name: String) : IStrategy diff --git a/client/src/main/kotlin/util/StrategyParams.kt b/client/src/main/kotlin/strategy/StrategyParams.kt similarity index 93% rename from client/src/main/kotlin/util/StrategyParams.kt rename to client/src/main/kotlin/strategy/StrategyParams.kt index 1a2a0806..e4442ced 100644 --- a/client/src/main/kotlin/util/StrategyParams.kt +++ b/client/src/main/kotlin/strategy/StrategyParams.kt @@ -1,4 +1,4 @@ -package util +package strategy import game.BidAction import game.GameSettings diff --git a/client/src/main/kotlin/strategy/StrategyUtil.kt b/client/src/main/kotlin/strategy/StrategyUtil.kt new file mode 100644 index 00000000..0fccd583 --- /dev/null +++ b/client/src/main/kotlin/strategy/StrategyUtil.kt @@ -0,0 +1,61 @@ +package strategy + +import com.fasterxml.jackson.module.kotlin.readValue +import game.GameMode +import java.util.UUID +import preference.PreferenceSetting +import preference.getPreference +import settings.Setting +import util.ClientGlobals.preferenceStore +import util.CpuStrategies +import util.EntCpuStrategies +import util.VectCpuStrategies +import utils.CoreGlobals + +fun getAllStrategies(gameType: GameMode, apiStrategies: List): List { + val inBuilt = + if (gameType == GameMode.Entropy) EntCpuStrategies.getAllStrategies() + else VectCpuStrategies.getAllStrategies() + + return apiStrategies + inBuilt.map(::InBuiltStrategy) +} + +fun getApiStrategiesFromPreferences(): List { + val apiStrategyJson = getPreference(PreferenceSetting.ApiStrategies) + if (apiStrategyJson.isEmpty()) { + return emptyList() + } + + return CoreGlobals.jsonMapper.readValue>(apiStrategyJson) +} + +fun saveApiStrategiesToPreference(strategies: List) { + preferenceStore.save( + PreferenceSetting.ApiStrategies, + CoreGlobals.jsonMapper.writeValueAsString(strategies), + ) +} + +fun saveStrategyErrorAndUnsetStrategies(id: UUID, error: String?) { + // Something has gone wrong, so save the API strategy as disabled + val strategies = getApiStrategiesFromPreferences() + val strategy = strategies.first { it.id == id }.copy(lastError = error) + val updated = strategies.update(id, strategy) + + saveApiStrategiesToPreference(updated) + + resetCpuStrategy(PreferenceSetting.OpponentOneStrategy, id) + resetCpuStrategy(PreferenceSetting.OpponentTwoStrategy, id) + resetCpuStrategy(PreferenceSetting.OpponentThreeStrategy, id) +} + +private fun resetCpuStrategy(strategySetting: Setting, id: UUID) { + val strategy = getPreference(strategySetting) + if (strategy.contains(id.toString())) { + preferenceStore.save(strategySetting, CpuStrategies.STRATEGY_BASIC) + } +} + +fun List.update(id: UUID, newStrategy: ApiStrategy) = map { + if (it.id == id) newStrategy else it +} diff --git a/client/src/main/kotlin/util/GameSimulator.kt b/client/src/main/kotlin/util/GameSimulator.kt index 4b2c6108..f206f264 100644 --- a/client/src/main/kotlin/util/GameSimulator.kt +++ b/client/src/main/kotlin/util/GameSimulator.kt @@ -7,6 +7,7 @@ import game.createAndShuffleDeck import `object`.Player import screen.ScreenCache.get import screen.SimulationDialog +import strategy.StrategyParams import utils.CoreGlobals.logger class GameSimulator(private val params: SimulationParams) { diff --git a/client/src/main/kotlin/util/SimulationParams.kt b/client/src/main/kotlin/util/SimulationParams.kt index a48174a6..e655915b 100644 --- a/client/src/main/kotlin/util/SimulationParams.kt +++ b/client/src/main/kotlin/util/SimulationParams.kt @@ -1,15 +1,16 @@ package util import game.GameSettings +import strategy.IStrategy data class SimulationParams( val settings: GameSettings, val opponentTwoEnabled: Boolean, val opponentThreeEnabled: Boolean, - val opponentZeroStrategy: String, - val opponentOneStrategy: String, - val opponentTwoStrategy: String, - val opponentThreeStrategy: String, + val opponentZeroStrategy: IStrategy, + val opponentOneStrategy: IStrategy, + val opponentTwoStrategy: IStrategy, + val opponentThreeStrategy: IStrategy, val enableLogging: Boolean, val randomiseOrder: Boolean, val forceStart: Boolean, diff --git a/client/src/main/kotlin/util/SimulationResults.kt b/client/src/main/kotlin/util/SimulationResults.kt index 8aa56023..6429fd53 100644 --- a/client/src/main/kotlin/util/SimulationResults.kt +++ b/client/src/main/kotlin/util/SimulationResults.kt @@ -1,6 +1,7 @@ package util import java.util.Vector +import strategy.IStrategy class SimulationResults { private var wins = 0.0 @@ -45,10 +46,10 @@ class SimulationResults { return MathsUtil.getPercentage(numerator, denominator, 2) } - fun generateRow(opponentNumber: Int, strategy: String, totalGames: Int): Vector { + fun generateRow(opponentNumber: Int, strategy: IStrategy, totalGames: Int): Vector { val row = Vector() row.add("" + opponentNumber) - row.add(strategy) + row.add(strategy.name) row.add("" + getWinRate(totalGames)) row.add("" + getChallengeRate()) row.add("" + getChallengeSuccessRate()) diff --git a/client/src/test/kotlin/TestUtils.kt b/client/src/test/kotlin/TestUtils.kt index 4b58842f..dedc6cd8 100644 --- a/client/src/test/kotlin/TestUtils.kt +++ b/client/src/test/kotlin/TestUtils.kt @@ -19,10 +19,10 @@ import kong.unirest.HttpMethod import kong.unirest.HttpStatus import online.screen.OnlineChatPanel import strategy.IRandom +import strategy.StrategyParams import testCore.makeGameSettings import util.CpuStrategies import util.SimulationParams -import util.StrategyParams fun getInfoDialog() = getOptionPaneDialog("Information") From 4684f4137790f69f1b738292226456b239d8de19 Mon Sep 17 00:00:00 2001 From: Alyssa Date: Fri, 5 Dec 2025 20:53:10 +0000 Subject: [PATCH 3/5] more strat wip --- client/src/main/java/screen/GameScreen.java | 24 ++-- client/src/main/java/screen/MainScreen.java | 6 +- .../main/java/screen/SimulationDialog.java | 35 +++-- client/src/main/java/util/ApiUtil.java | 24 ---- client/src/main/java/util/CpuStrategies.java | 42 ------ client/src/main/java/util/ReplayFileUtil.java | 17 +-- .../kotlin/preference/PreferenceSetting.kt | 20 +++ .../preference/PreferencesPanelPlayers.kt | 124 +++++++----------- .../src/main/kotlin/strategy/ApiStrategy.kt | 4 +- client/src/main/kotlin/strategy/IStrategy.kt | 7 +- .../main/kotlin/strategy/InBuiltStrategy.kt | 2 +- .../src/main/kotlin/strategy/StrategyUtil.kt | 50 +++++-- client/src/test/kotlin/TestUtils.kt | 10 +- .../test/kotlin/strategy/ApiStrategyTest.kt | 37 ++++++ .../kotlin/util/GameSimulatorBenchmarkTest.kt | 9 +- .../test/kotlin/util/SimulationResultsTest.kt | 3 +- core/src/main/java/util/Registry.java | 3 - 17 files changed, 195 insertions(+), 222 deletions(-) create mode 100644 client/src/test/kotlin/strategy/ApiStrategyTest.kt diff --git a/client/src/main/java/screen/GameScreen.java b/client/src/main/java/screen/GameScreen.java index 772b7961..b69f5631 100644 --- a/client/src/main/java/screen/GameScreen.java +++ b/client/src/main/java/screen/GameScreen.java @@ -5,6 +5,7 @@ import game.*; import object.Player; import preference.PreferenceSetting; +import strategy.InBuiltStrategy; import strategy.StrategyParams; import util.*; @@ -20,6 +21,7 @@ import static game.RegistryUtilKt.writeActions; import static preference.PreferenceSettingKt.getPreference; import static screen.ScreenCacheKt.IN_GAME_REPLAY; +import static strategy.StrategyUtilKt.getStrategy; import static util.ClientGlobals.achievementStore; import static utils.CoreGlobals.logger; @@ -313,9 +315,9 @@ private void getNewGameVariablesFromRegistry() handicapAmount = getPreference(PreferenceSetting.HandicapAmount); opponentTwo.setEnabled(getPreference(PreferenceSetting.OpponentTwoEnabled)); opponentThree.setEnabled(getPreference(PreferenceSetting.OpponentThreeEnabled)); - opponentOne.setStrategy(getPreference(PreferenceSetting.OpponentOneStrategy)); - opponentTwo.setStrategy(getPreference(PreferenceSetting.OpponentTwoStrategy)); - opponentThree.setStrategy(getPreference(PreferenceSetting.OpponentThreeStrategy)); + opponentOne.setStrategy(getStrategy(PreferenceSetting.OpponentOneStrategy)); + opponentTwo.setStrategy(getStrategy(PreferenceSetting.OpponentTwoStrategy)); + opponentThree.setStrategy(getStrategy(PreferenceSetting.OpponentThreeStrategy)); settings = new GameSettings( getGameMode(), @@ -459,9 +461,6 @@ protected void roundEnded(int playerLastToAct) protected void saveRoundForReplay() { inGameReplay.putInt(REPLAY_INT_GAME_MODE, ReplayConstantsKt.toReplayConstant(getGameMode())); - inGameReplay.put(REPLAY_STRING_OPPONENT_ONE_STRATEGY, opponentOne.getStrategy()); - inGameReplay.put(REPLAY_STRING_OPPONENT_TWO_STRATEGY, opponentTwo.getStrategy()); - inGameReplay.put(REPLAY_STRING_OPPONENT_THREE_STRATEGY, opponentThree.getStrategy()); int roundsSoFar = inGameReplay.getInt(REPLAY_INT_ROUNDS_SO_FAR, 0) + 1; inGameReplay.putInt(REPLAY_INT_ROUNDS_SO_FAR, roundsSoFar); @@ -552,11 +551,6 @@ protected void saveGame() //save the current player savedGame.putInt(SAVED_GAME_INT_CURRENT_PLAYER, currentPlayer.getPlayerNumber()); - //save strategies - savedGame.put(SAVED_GAME_STRING_OPPONENT_ONE_STRATEGY, opponentOne.getStrategy()); - savedGame.put(SAVED_GAME_STRING_OPPONENT_TWO_STRATEGY, opponentTwo.getStrategy()); - savedGame.put(SAVED_GAME_STRING_OPPONENT_THREE_STRATEGY, opponentThree.getStrategy()); - //exitedOnChallenge stuff boolean exitedOnChallenge = currentlyOnChallenge; @@ -627,9 +621,9 @@ public void continueGame(BidListCellRenderer bidRenderer) displayHands(); //set the strategies - opponentOne.setStrategy(savedGame.get(SAVED_GAME_STRING_OPPONENT_ONE_STRATEGY, "Basic")); - opponentTwo.setStrategy(savedGame.get(SAVED_GAME_STRING_OPPONENT_TWO_STRATEGY, "Basic")); - opponentThree.setStrategy(savedGame.get(SAVED_GAME_STRING_OPPONENT_THREE_STRATEGY, "Basic")); + opponentOne.setStrategy(getStrategy(PreferenceSetting.OpponentOneStrategy)); + opponentTwo.setStrategy(getStrategy(PreferenceSetting.OpponentTwoStrategy)); + opponentThree.setStrategy(getStrategy(PreferenceSetting.OpponentThreeStrategy)); personToStart = savedGame.getInt(SAVED_GAME_INT_PERSON_TO_START, 0); handPanel.assignAsteriskToStartingPlayer(personToStart); @@ -1125,7 +1119,7 @@ public void run() String info = opponent.getName() + " has had their strategy reset to " + CpuStrategies.STRATEGY_BASIC; DialogUtil.showInfo(info); - opponent.setStrategy(CpuStrategies.STRATEGY_BASIC); + opponent.setStrategy(new InBuiltStrategy(CpuStrategies.STRATEGY_BASIC)); action = CpuStrategies.processOpponentTurn(parms, opponent); } diff --git a/client/src/main/java/screen/MainScreen.java b/client/src/main/java/screen/MainScreen.java index e1f2696d..defb4783 100644 --- a/client/src/main/java/screen/MainScreen.java +++ b/client/src/main/java/screen/MainScreen.java @@ -39,6 +39,7 @@ import static screen.ScreenCacheKt.IN_GAME_REPLAY; import static screen.online.PlayOnlineDialogKt.showPlayOnlineDialog; import static util.ClientGlobals.achievementStore; +import static util.ClientGlobals.preferenceStore; import static utils.CoreGlobals.logger; import static utils.ThreadUtilKt.dumpThreadStacks; @@ -675,9 +676,8 @@ public String processCommand(String command) } else if (command.startsWith("server ")) { var serverCommand = command.replace("server ", ""); ClientGlobals.INSTANCE.getDevApi().doServerCommand(serverCommand); - } else if (command.equals("keygen")) { - var key = KeyGeneratorUtil.generateSymmetricKey(); - textToShow = EncryptionUtil.convertSecretKeyToString(key); + } else if (command.equals("clearprefs")) { + preferenceStore.clear(); } else if (command.equals("simulator")) { diff --git a/client/src/main/java/screen/SimulationDialog.java b/client/src/main/java/screen/SimulationDialog.java index 08235c13..77b64c13 100644 --- a/client/src/main/java/screen/SimulationDialog.java +++ b/client/src/main/java/screen/SimulationDialog.java @@ -1,5 +1,6 @@ package screen; +import bean.ComboBoxItem; import bean.NumberField; import game.GameMode; import game.GameSettings; @@ -13,6 +14,8 @@ import java.util.HashMap; import java.util.Vector; +import static strategy.StrategyUtilKt.getSelectedStrategy; +import static strategy.StrategyUtilKt.getStrategiesComboBoxModel; import static utils.CoreGlobals.logger; public class SimulationDialog extends JDialog @@ -176,10 +179,10 @@ public SimulationDialog() private final JPanel cpuPanel = new JPanel(); private final JCheckBox cbOpponentTwo = new JCheckBox(); private final JCheckBox cbOpponentThree = new JCheckBox(); - private final JComboBox opponentOneStrat = new JComboBox<>(); - private final JComboBox opponentTwoStrat = new JComboBox<>(); - private final JComboBox opponentThreeStrat = new JComboBox<>(); - private final JComboBox opponentZeroStrat = new JComboBox<>(); + private final JComboBox> opponentOneStrat = new JComboBox<>(); + private final JComboBox> opponentTwoStrat = new JComboBox<>(); + private final JComboBox> opponentThreeStrat = new JComboBox<>(); + private final JComboBox> opponentZeroStrat = new JComboBox<>(); private final JLabel lblTimeTaken = new JLabel("