From 1cb5c0923ba7baee9b2ba4e72032d85c5e754f57 Mon Sep 17 00:00:00 2001 From: Hymmel Date: Tue, 10 Feb 2026 14:17:25 +0100 Subject: [PATCH] p --- ai-client/build.sh | 14 + ai-client/pom.xml | 35 ++ .../java/com/lona/tictactoe/client/Main.java | 406 ++++++++++++++++++ ai-client/target/ai-client-1.0-SNAPSHOT.jar | Bin 0 -> 11313 bytes .../com/lona/tictactoe/client/Main.class | Bin 0 -> 16615 bytes .../target/maven-archiver/pom.properties | 5 + .../compile/default-compile/createdFiles.lst | 1 + .../compile/default-compile/inputFiles.lst | 1 + .../original-ai-client-1.0-SNAPSHOT.jar | Bin 0 -> 11069 bytes .../lona/tictactoe/server/GameInstance.java | 24 +- .../lona/tictactoe/server/GameInstance.class | Bin 4238 -> 4363 bytes server/target/maven-archiver/pom.properties | 2 +- .../target/original-server-1.0-SNAPSHOT.jar | Bin 9650 -> 9744 bytes server/target/server-1.0-SNAPSHOT.jar | Bin 9948 -> 10042 bytes .../com/lona/tictactoe/web/TcpSession.java | 12 +- .../com/lona/tictactoe/web/TcpSession.class | Bin 2752 -> 3960 bytes web-client/target/web-client-1.0-SNAPSHOT.jar | Bin 22319653 -> 22320220 bytes .../web-client-1.0-SNAPSHOT.jar.original | Bin 10681 -> 11248 bytes 18 files changed, 496 insertions(+), 4 deletions(-) create mode 100755 ai-client/build.sh create mode 100644 ai-client/pom.xml create mode 100644 ai-client/src/main/java/com/lona/tictactoe/client/Main.java create mode 100644 ai-client/target/ai-client-1.0-SNAPSHOT.jar create mode 100644 ai-client/target/classes/com/lona/tictactoe/client/Main.class create mode 100644 ai-client/target/maven-archiver/pom.properties create mode 100644 ai-client/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 ai-client/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 ai-client/target/original-ai-client-1.0-SNAPSHOT.jar diff --git a/ai-client/build.sh b/ai-client/build.sh new file mode 100755 index 0000000..a3fa2bd --- /dev/null +++ b/ai-client/build.sh @@ -0,0 +1,14 @@ +#!/bin/bash +echo "Building AI Client..." +mvn clean package + +if [ $? -eq 0 ]; then + echo "--------------------------------------------------" + echo "Build Successful!" + echo "Run AI Client:" + echo "java -jar target/ai-client-1.0-SNAPSHOT.jar [host] [port]" + echo "--------------------------------------------------" +else + echo "Build Failed!" + exit 1 +fi diff --git a/ai-client/pom.xml b/ai-client/pom.xml new file mode 100644 index 0000000..57bbf15 --- /dev/null +++ b/ai-client/pom.xml @@ -0,0 +1,35 @@ + + 4.0.0 + com.lona.tictactoe + ai-client + 1.0-SNAPSHOT + + 17 + 17 + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.0 + + + package + + shade + + + + + com.lona.tictactoe.client.Main + + + + + + + + + diff --git a/ai-client/src/main/java/com/lona/tictactoe/client/Main.java b/ai-client/src/main/java/com/lona/tictactoe/client/Main.java new file mode 100644 index 0000000..b94e4d3 --- /dev/null +++ b/ai-client/src/main/java/com/lona/tictactoe/client/Main.java @@ -0,0 +1,406 @@ +package com.lona.tictactoe.client; + +import javax.swing.*; +import java.awt.*; +import java.io.*; +import java.net.Socket; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Main extends JFrame { + private Socket socket; + private PrintWriter out; + private BufferedReader in; + + private CardLayout cardLayout = new CardLayout(); + private JPanel mainPanel = new JPanel(cardLayout); + + // Menu Components + private JTextField joinCodeField = new JTextField(10); + + // Game Components + private JButton[] buttons = new JButton[9]; + private JLabel statusLabel = new JLabel("Connecting..."); + private JLabel codeLabel = new JLabel("Code: -"); + private boolean myTurn = false; + private char mySymbol = ' '; // assigned by server implied turn + + public static void main(String[] args) { + String host = "38.242.130.81"; + int port = 1870; + + if (args.length > 0) { + host = args[0]; + } + if (args.length > 1) { + try { + port = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + System.err.println("Invalid port number provided, using default 1870"); + } + } + + final String serverHost = host; + final int serverPort = port; + + System.out.println("Starting TicTacToe Client..."); + System.out.println("Target Server: " + serverHost + ":" + serverPort); + + SwingUtilities.invokeLater(() -> { + try { + Main client = new Main(serverHost, serverPort); + client.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Failed to start GUI: " + e.getMessage()); + } + }); + } + + // Instance variables + private final String serverHost; + private final int serverPort; + + public Main(String host, int port) { + super("TicTacToe Client"); + this.serverHost = host; + this.serverPort = port; + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(400, 500); + setLocationRelativeTo(null); + + try { + initUI(); + setContentPane(mainPanel); + connectToServer(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void initUI() { + // --- MENU PANEL --- + JPanel menuPanel = new JPanel(new GridBagLayout()); + JButton createBtn = new JButton("Create Game"); + JButton joinBtn = new JButton("Join Game"); + + createBtn.addActionListener(e -> send("CREATE")); + joinBtn.addActionListener(e -> { + String code = joinCodeField.getText().trim(); + if (!code.isEmpty()) + send("JOIN " + code); + }); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 5, 5, 5); + gbc.gridx = 0; + gbc.gridy = 0; + menuPanel.add(createBtn, gbc); + + gbc.gridy = 1; + menuPanel.add(new JLabel("Enter Code:"), gbc); + gbc.gridy = 2; + menuPanel.add(joinCodeField, gbc); + gbc.gridy = 3; + menuPanel.add(joinBtn, gbc); + + // --- GAME PANEL --- + JPanel gamePanel = new JPanel(new BorderLayout()); + + JPanel topPanel = new JPanel(new GridLayout(2, 1)); + topPanel.add(statusLabel); + topPanel.add(codeLabel); + gamePanel.add(topPanel, BorderLayout.NORTH); + + JPanel boardPanel = new JPanel(new GridLayout(3, 3)); + for (int i = 0; i < 9; i++) { + int finalI = i; + buttons[i] = new JButton(""); + buttons[i].setFont(new Font("Arial", Font.BOLD, 40)); + buttons[i].setFocusPainted(false); + buttons[i].addActionListener(e -> { + int r = finalI / 3; + int c = finalI % 3; + send("MOVE " + r + " " + c); + }); + boardPanel.add(buttons[i]); + } + gamePanel.add(boardPanel, BorderLayout.CENTER); + + // --- BUTTONS PANEL --- + JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 10, 0)); + + JButton leaveBtn = new JButton("Leave Lobby"); + leaveBtn.setBackground(Color.GRAY); + leaveBtn.setForeground(Color.WHITE); + leaveBtn.addActionListener(e -> { + send("LEAVE"); + resetGame(); + }); + + JButton surrenderBtn = new JButton("Surrender"); + surrenderBtn.setBackground(new Color(220, 53, 69)); // Bootstrap Danger Red + surrenderBtn.setForeground(Color.WHITE); + surrenderBtn.addActionListener(e -> send("SURRENDER")); + + buttonPanel.add(leaveBtn); + buttonPanel.add(surrenderBtn); + + gamePanel.add(buttonPanel, BorderLayout.SOUTH); + + mainPanel.add(menuPanel, "MENU"); + mainPanel.add(gamePanel, "GAME"); + } + + // AI Configuration + private static final String API_KEY = "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"; + private static final String MODEL = "arcee-ai/trinity-large-preview:free"; + private char[] boardState = new char[9]; // Keep track of board state + + private void connectToServer() { + new Thread(() -> { + try { + System.out.println("Attempting to connect to " + serverHost + ":" + serverPort); + socket = new Socket(serverHost, serverPort); + out = new PrintWriter(socket.getOutputStream(), true); + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + System.out.println("Connected successfully!"); + SwingUtilities.invokeLater(() -> statusLabel.setText("Connected to Server.")); + + String line; + while ((line = in.readLine()) != null) { + System.out.println("Received: " + line); // Log received messages + processMessage(line); + } + } catch (IOException e) { + System.err.println("Connection Error: " + e.getMessage()); + SwingUtilities.invokeLater(() -> { + statusLabel.setText("Connection Failed."); + JOptionPane.showMessageDialog(this, "Connection Error: " + e.getMessage()); + // Don't reset to menu if we can't connect, let user see error + }); + } + }).start(); + } + + private void send(String msg) { + if (out != null) + out.println(msg); + } + + private void processMessage(String msg) { + SwingUtilities.invokeLater(() -> handleMessage(msg)); + } + + private void handleMessage(String msg) { + String[] parts = msg.split(" "); + String cmd = parts[0]; + + switch (cmd) { + case "GAME_CREATED": + cardLayout.show(mainPanel, "GAME"); + if (parts.length > 1) { + codeLabel.setText("Code: " + parts[1]); + mySymbol = 'X'; // Creator starts as X usually + statusLabel.setText("Game Created. Waiting for opponent..."); + } + break; + case "JOIN_SUCCESS": + cardLayout.show(mainPanel, "GAME"); + mySymbol = 'O'; // Joiner is O + statusLabel.setText("Joined Game."); + codeLabel.setText("Code: " + joinCodeField.getText()); + break; + case "START": + statusLabel.setText("Game Started! X goes first."); + break; + case "RESTART": + for (int i = 0; i < 9; i++) { + buttons[i].setText(""); + boardState[i] = ' '; + } + statusLabel.setText("Game Restarted! X goes first."); + break; + case "BOARD": // BOARD X O X ... + String boardStr = msg.substring(6); // remove "BOARD " + for (int i = 0; i < 9 && i < boardStr.length(); i++) { + char c = boardStr.charAt(i); + boardState[i] = c; + buttons[i].setText(String.valueOf(c)); + } + break; + case "TURN": + if (parts.length > 1) { + char turn = parts[1].charAt(0); + if (turn == mySymbol) { + statusLabel.setText("AI Turn (" + mySymbol + ")... Thinking..."); + makeAiMove(); + } else { + statusLabel.setText("Opponent's Turn (" + turn + ")"); + } + } + break; + case "WIN": + String winner = msg.substring(4); + statusLabel.setText("Winner: " + winner); + // Auto RESTART if AI loses? Or wait for user? Let's just create a dialog but + // maybe auto-accept if we want seamless play? No, user requested seamless + // winning. + // Let's just wait for user to restart. + JOptionPane.showMessageDialog(this, "Winner: " + winner); + break; + case "DRAW": + statusLabel.setText("Draw!"); + JOptionPane.showMessageDialog(this, "Draw!"); + break; + case "OPPONENT_LEFT": + JOptionPane.showMessageDialog(this, "Opponent left the game."); + resetGame(); + break; + case "ERROR:": + if (msg.contains("It is not your turn")) { + statusLabel.setText("Not your turn!"); + } else { + // Start thinking again if move was invalid? + if (msg.contains("Invalid") || msg.contains("occupied")) { + makeAiMove(); // Retry + } + System.err.println("Server Error: " + msg); + } + break; + } + } + + private void makeAiMove() { + new Thread(() -> { + try { + Thread.sleep(2000); // Wait 2s + + String prompt = buildPrompt(); + System.out.println("Sending Prompt to AI:\n" + prompt); + + String response = callOpenRouter(prompt); + System.out.println("AI Response: " + response); + + // Parse response: expecting row, col + // The prompt will ask specifically for "row col" format + String[] coords = parseCoordinates(response); + if (coords != null) { + send("MOVE " + coords[0] + " " + coords[1]); + } else { + System.err.println("Failed to parse AI move. Retrying random..."); + makeRandomMove(); + } + + } catch (Exception e) { + e.printStackTrace(); + makeRandomMove(); + } + }).start(); + } + + private void makeRandomMove() { + // Fallback: pick first empty spot + for (int i = 0; i < 9; i++) { + if (boardState[i] == ' ') { + int r = i / 3; + int c = i % 3; + send("MOVE " + r + " " + c); + return; + } + } + } + + private String buildPrompt() { + StringBuilder sb = new StringBuilder(); + sb.append("Play Tic-Tac-Toe as '").append(mySymbol).append("'.\n"); + sb.append("Board:\n"); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + char c = boardState[i * 3 + j]; + sb.append(c == ' ' ? '_' : c).append(" "); + } + sb.append("\n"); + } + sb.append( + "Respond ONLY with the coordinates of your next move in JSON format: {\"row\": <0-2>, \"col\": <0-2>}. Do not add any other text."); + return sb.toString(); + } + + private String callOpenRouter(String prompt) throws IOException, InterruptedException { + HttpClient client = HttpClient.newHttpClient(); + String jsonBody = "{" + + "\"model\": \"" + MODEL + "\"," + + "\"messages\": [{\"role\": \"user\", \"content\": \"" + + prompt.replace("\n", "\\n").replace("\"", "\\\"") + "\"}]," + + "\"temperature\": 0.2" // Lower temperature for more deterministic/structured output + + "}"; + + HttpRequest request = HttpRequest.newBuilder() + .uri(java.net.URI.create("https://openrouter.ai/api/v1/chat/completions")) + .header("Authorization", "Bearer " + API_KEY) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + String body = response.body(); + // System.out.println("DEBUG RAW BODY: " + body); // excessive logging, but + // helpful if needed + + // Parse content + int contentIndex = body.indexOf("\"content\":"); + if (contentIndex != -1) { + int start = body.indexOf("\"", contentIndex + 10) + 1; + // Find the end quote, handling escaped quotes + int end = start; + while (true) { + end = body.indexOf("\"", end + 1); + if (body.charAt(end - 1) != '\\') { + break; + } + } + String content = body.substring(start, end); + return content.replace("\\n", "\n").replace("\\\"", "\""); + } + return ""; + } + + private String[] parseCoordinates(String text) { + // Look for JSON pattern first: "row": 1, "col": 2 + Pattern jsonPattern = Pattern.compile("\"row\"\\s*:\\s*(\\d)\\s*,\\s*\"col\"\\s*:\\s*(\\d)"); + Matcher m = jsonPattern.matcher(text); + if (m.find()) { + return new String[] { m.group(1), m.group(2) }; + } + + // Fallback: strictly row col numbers + m = Pattern.compile("(\\d)\\s+(\\d)").matcher(text); + if (m.find()) { + return new String[] { m.group(1), m.group(2) }; + } + + // One last fallback: just find any two digits + m = Pattern.compile("(\\d)[^\\d]+(\\d)").matcher(text); + if (m.find()) { + return new String[] { m.group(1), m.group(2) }; + } + + return null; + } + + private void resetGame() { + cardLayout.show(mainPanel, "MENU"); + for (JButton btn : buttons) + btn.setText(""); + for (int i = 0; i < 9; i++) + boardState[i] = ' '; + statusLabel.setText("Connected."); + codeLabel.setText("Code: -"); + } +} diff --git a/ai-client/target/ai-client-1.0-SNAPSHOT.jar b/ai-client/target/ai-client-1.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..0690cc5f09c74e0e8ff4f0155538076b11bc7920 GIT binary patch literal 11313 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 literal 0 HcmV?d00001 diff --git a/ai-client/target/maven-archiver/pom.properties b/ai-client/target/maven-archiver/pom.properties new file mode 100644 index 0000000..a77a248 --- /dev/null +++ b/ai-client/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Tue Feb 10 14:17:06 CET 2026 +artifactId=ai-client +groupId=com.lona.tictactoe +version=1.0-SNAPSHOT diff --git a/ai-client/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/ai-client/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..0128c4a --- /dev/null +++ b/ai-client/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1 @@ +com/lona/tictactoe/client/Main.class diff --git a/ai-client/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/ai-client/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..7812269 --- /dev/null +++ b/ai-client/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1 @@ +/home/collin/tictactoe/ai-client/src/main/java/com/lona/tictactoe/client/Main.java diff --git a/ai-client/target/original-ai-client-1.0-SNAPSHOT.jar b/ai-client/target/original-ai-client-1.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..fbc03a56f51938ca0e7b0a764aaaa9b6561760fc GIT binary patch literal 11069 zcmbVy1yo$iwk;MUXmFQc2`-IGLvV-2-QC?GIHU;>G&sTCCAho0I|O(4Pu_j!oICD4 z_l@`d>fXC*j9zor+O?}@+mx4rhItF|J186^wf?K~-zS9ERz^fgkX}Molu`b_)8HY< zU(={zwa2YqU-o}JF#kDCMo?BlR76pUK}PgKW@u1aik@K{S&E)!WN5Ss#5Bdaw(USC zInqZbMgIvNZYx_Q7Mr$>!mU0948o8CDLSRnlwcAfqQ|g;u)Ht^K^K_eS9F&{?)52> ztd5dxmHl^IT#4>z-!QeyVy$T3kY~_)1Pg%O>LLE94&uM6doAeCfO+j1+FJiv|G#Ja zzRcelR<<_!|3ezaKc_jF8#?J5I@uck4*>kX2N+tJ8{0VjiTlTV(#?X6)Zaru>kqL|v-+Ygif(|(di2D($aW4Q_6VbPWt)`E08^jg zH$ke&+Y-Mcze+pO%A8_`=<>QbW~wR&y^;#BH@o{S3YuUS^PhYC*jn+S~|{l>lJ8a56=^3}z7TNr9x zD3?l!TZT!xIP=8tA>2>R<7yow<3+cghT}&+WE&mRS{WmbZh4MM1#~&rb<2&;yclIN zv;wF!0AW-fP!L;734=IY>?~SsUXk40IUs4`B|;Ghx!`P}X6YDh=)R3Tu7??&(Z* z0Kq};efeldWYYWuP8bY#hf7?-FOZ*L5H^+q^CTu-WfffuIR(acJ;S@VA?RcT5B+aN zYQ^g2ulxexy+MN99zh2(G=8TM{M88qW-WqbNY-W85Zgul#^5b-wOK8k^RIWg5~3u zCTPGG=4^^4s4CM{iBwZ0QW)S8<0Lm>vE*jf3T~qip62S{k=QrDo-KxaDUeNh{vLuqns;%Zm4bLt`;{cH?*nViW>DewtSl1a^X4#tso~R{%tMJCQ&Lb+Q7(S&_%Nzlh`hXcQ zA!Q;K!;~e;Ko}7{N4YvY*k}n<0SuM91`ROOT^TcDL36^Qfui<#u?xix@=NrJBe$wkqQj8(f16)=&w!`#j3v~&&8{KEk3Ez)=xSa2?p z40ZHp0}JOkiS(LXnjfqT-!Y9etCdNnGDeY;f0#%N$a$Khdaq#vG}aDX+ab0MPgH zc`}de4ZWGR6Lr-}#<6={Bi%(MawxaEisY z$pCTqp59CjL{1GfM1rJZeBQLr&ULu!FKbgZLrF|6`W@A_@-K{!r%RNL+ah}`XReN) z=*Z4nwKhG{V)Y?uENaUKv8)u-dCG^6 z@u1*tVtXAtdq1<&Gb^ZO`(Mms4nlOXXs+$*5MfqCUr}S0`7<^uDx2-4ErAZ6=BI`Y z$jQ9Kf;}hOglT$qrQI0r6W^lLCOn*&3&px6*&)_^!#`$Zq=Ir#;RBde% zucpzm%JPKCxfZUbREgq8;fI0T{di?6XorTynHoS6(%9~Te8?xfB$XN^TPAl%rILdB z`htqu3TsF2BMWKm(63Xq)qol$D5P_9Y*i+hy$Dw^SHh!>;4CffuH!6eowtv}ang}HON=$T2&J(34 zukx{Z(tHSEG;HmmIXW~py@~9_zz&EL+gL0O^BYyds=WF6T~i1`#?EfrUcI<3|t>>P_Qf z*o;>WaB#@S)pPM`?0fK!bJ=I&=o{fUL}uli_M~UZp>M|NsleXFU*5P30k{I|Wg<8q z^&4r|<(w9u=_Lf|wym*4j8PMr2`aIOlaN9a6%$TFHlD=+>tej%I}C_4hcO*6qn?CU zfCL*j(&){73fr1AEmBVejI}l4+QeMXxKeq}kzQ;}SyB^5S7y7Ou5Dj%Cqbu_Hvn5d ztmjOmBOmNn2*Z{;Ihf;B&`pBV?9{vNjr<(gnK!%tBR0OE2e-?*?xrcChy?{<8DLe2f1*>7=1lLrVOJeP)V^bmIf17Y*9~_o z7!X3o-zQMU3Up|c?{2|u>gw<(M@U_gAn|J}^0UaS7z^SCv)(c1{)%%Uh4uboOB>cB zSx)OQIe`R zeA^h^s9hOZ5XfdNt_L|0R`#NlqQhNU{`7oCR$PODE9F-Ar`EvZb&Jzwy{*G;9cgv6 zfty4P!sHgXGK1J$6N*{=jM$G##YWo-dR!u*_fces{ffpCoGPO|acx?Crb{uC)7V-Z zLuQNMRX?}Y>es$dW%~t3c|*0lpbD+b{ni`@SU5lUvgV8b7}5Q*;TmFSsQVt1K?ue0 zgw7I$Vl5u+7};LrN4a-LluWoL;W0Tz9@B`tWvrBdcJP)_bMAn^%J(htiYDnGOpD@J_O!Z!3#~k4 zgvivd)!C*-=7z|q%la>QA!I8)()_G^S}$edzi(CX*Dn$qil>lA z;eXKlsBQyozug<*%!ZZm4qIuN+6nFN#17_la*Et4*ayrDypgUUefsYBc9y`R|CETx zL-pF(d7inkN<<7pNEu}l;&NI9gb}k`Sz#QnQL6IUaBeOi(qWUOvP^-9a~R|tY*nOj zo#q1XBt@^n#$q;97ZGd?MDQtX7KZxbVK;BLcx z$NF<3e-cDauLg3w#Z;fH4etK8xVsM=1=*(Rg(6-2wH(-SVG&En)9f@aWtRB$D9R-k z%{lDwY>aNv6ER^>8`K4kbV)hvEZ&C{C$JIOJ}C!~&J583>&Z7}UFlQzAVuq7IASiI zVp8`+aN1|Bv0_W}0&6YhMT0`p@Wz%}4{!RE!bKmm7}rHd>8hQhY-aZK>|0To$Eu># zx!R5Vgn>A*6pdLb=6h~pl=4CB+|xMuRHp?)cztyS&Va0d=WF=tkV4>u&w4SG@*&JS zAoXzO?%@o{`=#c4f=*oTk`=UF=lDJ%wr%+6uwyjwd!S@9DG$t70bFs7iS;33o{1f= zv;pb&2XSG2rz~Q=(Eb$LSuw=x3loq>iTn=p4u{4qtiD(91v zr}^bePWzO_x2MVm4&7;-Xyk^j|zYzPsg!0>u|n0?qdk$`f69I)9ok zghAkPt{)c4%A-$RiEl#-yH*=MBlOYnsLZQ;uI9)Qu@_n%bsFgVa92$NzPjoN%Z5eh zy&_VMPvLlzbRK~SZhJ~|dg|1J3qKJTM!JLLA|u@0+eI3}uZK#i(Q7%?Wr8x|?%xAW zP>=ctBpzN8UR_yW8>H|MewoW+bQXJ<-W=8PGWw2x1fC`F#WpzR%%i;%w3#uNW{tQY zD{%2V=h2b8--9C*au{c(7l42EZ-~^`&X?F;lVRFhjyQ}Wn2n|Q^i3Vjua0d2&b2|K zb3@vmBBv5pU}?Y%Kz6;ds7HQw6rQ{s5F3V$xctaqX3N8JHwFTEBaD3 zebZx{pOCY@6Yn89>+`WjSAGAZ_QTgHorMH8U z*Swy@{dCSN*du*Fs;{4Ef7P9(VMRW`VA*%D;iX~klMx6B#4Qy6on|GK)zDCL{s&B=BuB3_=r{UCon9O1Sr-p zCVSbkHCyU?R#6AjP_9jrixR}(yG~sHUCWs2zn(Bds zVm{h>sdxh#O3FB7K=w^x8zz%TBt)Gdz(7K&OxSvP%Mbdh>*6uZrM$D4oov$%GLB@k z{Xi3^=30I_f?a%md6m)Kg{qgANZ0e!eo8ss8(}&@w<3(mLIk)C`#TJBa%TdL>%JoL z&N$x`f;hkpgfbjdglL$D>vWJ*jU3FL#=G?FUWpBhp`^;Q|w^HILxrx=W z15w_lG0}%;l$5#@+w@$KrHonI_u5iLSB>A2E*rnj?A_EmrTM_6y5d-mpOjQ1+onHu zgMDoCh}`59?5ETzFY&$ePjHo2!`$C}$>dFBnGUkR@nCrW6WQUL7AD}~r%%)P&!*jP zj4=vZG-Zq)UEVx0bPfq5q_gMVMrMdu`v5HHaB^}Gn??4r1 zIB1A~+Y+|-(PcUVm~$JHya}DkEo(Hr{kM>i_hTG1GNVHhW!xQ^j^y{ zvt!QHz3T^DYovZs#AY3C1CS)tAcSo{SH=9`To9{F0KZJ$*J_+3C8_1HT4D{vm8o$N zC#rn5vF)*DzO{34p7lA_jjBQd~U7<_p!h3WcJ@W=d`Fd^sm>)0!G<< zsiU}&-ZKQmzl{k)Uf2xgWytH6U}(%V0%8Aria)(1)kehDg{z$*$^PZCdKGZl4Xb^R zF8TH1OYkn0LMdZHMzv}J%7pcI2eBNUQSYc@D~>bUsFs%WmTx<-$*m>nH#nn%j;LeL zymgv18rZ0xuw@N{0shTbvdiRG=-LuC`=lyvxXFb>;xi=Xqjsnhh7%k87ka;XAn%W1 zwcqZ7MALe2o~ACv7Wjxwf36oYISwBVH9Ogqs(%YZps&y6UyI??v#iwdiAuA$;oBTx zz|AH>8AFsUvi$6GhzWLJ4cRsJe&+2oj|pOAbzfa?R$DoJa+o?l4!0_^jPjx95ih+a zC{{^KOmGJ_a|_t^J;*^{&NfMxU)iE)GVh$x=II)z$7}P5zr-TwnEK;j ztjHX94h>G3a$Gc_ph~Z{Rv?To8mxNCeq`*t(ZxK$;F-qffdNx2K=|6RUse;f=#c|l zFfOwKMm|TdD^izG6VPktJ1fG!90krc!uXs>zMb63Xq{DLT!thf4us{GMeqo|-|Zc1 z=U_Uwosv5l3p&iz<_%)ln0I1k%#}N(S?D*NFkX^Wwd3$k+PuVD5lP>cn^1n_Y6!N? zw!9<0hXM-Bo@F^f10{5~cJ@Sl5^a91PS8K9HYjU$83SN1lc)14bf}soAg}OZrN_;B z*?Z1t_p8cTDWo1ToZ}XtpMY`c3h6@qBBrNxQ`7qw6#DjyU2P& zj2T9Hk?Ek>A4UdwjZ;_Olf(E*6*)4trfb07h49X~jw{N&stJ8Oc@^MWV7*Y`G|*xBY8(q?ppEbR`kbJ>ul|xx0{IyD0 zMd1uB(tcy`)TX)N;K7XqUxbVH^(lduWr~X7bkdEVSlPTmI6|za+sUiyZYYtXsch5+ zce-UO5RVSmG^%yGq3zZxyL5@R5*h7#P1B^CUC(2DWLuBY>(co=Zs8+b~zM(y}zh;>H2KgD%S0C_^LKK zW%sfERg)R99?U9@jze0bS7<_;y`8ec^*lQKy0D|$oBap3*>^EtDw9D^rhRVGIHr7U zv>_6Qn>GE<(+!~Q!qY8}uKu)4@2tF~o2}2p=%Q7=%f`fR{j<@m`8L?qNVk+ifjXp!_ZB{fsCvICyCydfhm#1J@Z;D z#Ia1}4@Cfx_~;F^^cdcA2-^j*%^a>-+>POWp)qPO@_gXX!uOEti#3tc#e& z<7k&ACrv)dtSlf*BGx|%GRSDn@+#b#&+S3=* z@v^&*9znjsW#_b)_%H9a>vo-=QJ*4Sq-;OnJPFEV0%?HF1#kD{ED-i-cNq(lRzQ}! z*3;6yibt2OSed^0Iv#K?kEIJTC++^LsvKkbS8U%;j*6%1=5ns9G>P;gJz|lsV7#`; zt_yKErJj;{-|vxx1o||Axl|wg8P3nEV#}VY;ELo_bUz_6$A!f2vP1J|{;&!3J=H_a z*{8b1S94Bkz_Si6H<^pfh`l7w_0V00nkwi6ofK-m(YGj@7H35v|KJ||vsYd>J`aL) zVCJPKk_70|pXqP_?KXO2o_j^+p7Y?X@yK6*`VRe$4?pYNu}6Byz8TIddn+=3g2%e$ zlv6gDdJ;EHZoY{$buu2+5Jk}b^TwK__F(RpW1P@TIqle^7aEzQeFVnz{XK03fb~7v z207+=^aF$8?!zGYKy+E>vN^mAR&2l;H-ZUQT*3rlX?DFCe%K-JjVPVGlKw#C1n7Gop{siPNa4I0@h4jRRWJ_*FD2tI`O)e}9`P9_G z4V8vq%&n$Ldoa)a8uZn&+o?%%+ia3|d2&=&X`Nxjc@S^-aQNW^`D{s^$zbfD7Ux=| zz#6``Vm_b$0uEpvvgP^p&2q3^WrNl3(jsYu)|`EIj8_jFGY5ZwH|trwLp5 zLQaJBLt9bU_}g5!PwP-my;09I{Ow3a*2PG+dbL0J07KHJx}%{Vrve_EGU4vTq~mP# zj-Vf_AfJ_uMRj@t9^XzHrjQG8h4=#7e9>CrvF1px7T2wscTi8$mv#^tO8cbQO&W4! zEIzn&B$(LV53BbQEVn~k(+j;mWfy2>TJGj^LcQte zVfaiQZh3a)@0^~Ce{Ggu7b2@#XMW2eUcc|c30cO({)RhE)z!>&J=b(9)q*6DC-qoW zcXn@A-6^a=YWZu645sR;{EYx}gE?X=gAIJtwbqr)QBupcnw`T`-N#NpuhLGnm4lyn zEegOB_FLsMswn={bK+t74ouXomBQmr$G370NH5TIRKct1owg)vtsFxE4le|WlrJ}; zNhxPcJJpSnOVD357ndpV&RaOd1Z#bPVftw?cs=C7N`*0PsSpiMry4jDFr3MsT4J#w zwN%b*EPf4|lly+*hM;#jH3dBzbxCJm5>X#T7QjvUoVp_gO@GFBN;$`sxJE>N4rwPD zN`xLom#uFj;bGW5#JqHq%YfVP@;)OUT<6I>%30dj+m1G|VEUomrArvXrNbjFh`oWg zI%BVzh@x_4Evnz8jveMe+KJn#Iw}3ki?yabFf0E?7ctZaxnzS;o?KUq;MT)id?!Mf z2x7!_(km&-A^74Rl1f_OtL>LEfHvauPm zoOvT>91&7GbL>(t6pvZJGn_7fR9VGU0SN`X)IyZ^j}3Z9xh=6#(;SfoL&Eyf)-3n$ zkzPWI<6w`N+mk{-cp^D53T}aLc@e@2k-67T3SoiNIhJX!|JA34DAF;!Bad-=%kb&E z`Ia(xDusd-wXpuE^J_q%U2Br6Q&iPhcH6JJW5F6TAOUX8&!-HHeSj)*;UwJjz*8YM zrlV5o7#@gZk_%OI3MK#k`d$d|@ndgpEMf8uk&ictOc{<9N5%|tK~-ug8AQ=KBA0}A znS4n^ER7#t=(Pfhcj~V(?dsU$V9XOimS-7?wVRI3Wig!b*PpebN;BZ1JWlc${dZ?~ zf5awTk5OEO#*f9pTPGBXUD0@oNsxn=UUEk8XpyIr;AZ%8iCu-qeue5eOt`Rz9c9;| zSa~|}bHmeeLohJ|BspUgI}%g02x+}IjMwwNO)U0HmfEEm#%57I4J&Z=OW+A^AYAc< zbg`Jmm?%VW>wX?nxF{p2!DFq#8y`G57$%fd&^VB<6exg>g=rx1?&3Q&Oo#3*B^H^M zRHy+dr7HpL@~H@^+23VYzY)+3YBcjG<$1FRy7XRnr{%ws6RJ)kma>#u$ucBc!mOZc zQO?kB@s`yKzgeP#S2T-*!{t( z;(=sy{M2+16`F*#k;i#C?vA1yc-_*N1p&+1XwO-`76MX(BqfGED26bZRCTFc?Mh%GqpSV`KDcz{;2C03S=cnW$o~5noBxA zZ~CAGm5!eH9E0yT5V3C zEO+KjPqBMRVK)W&twUuECO`NIPU_R7RsD+k*douLQU5a2{Hr4f_0^j4rz6N(-^JMG zPan&_+lOB5EdQGPYO`VZZL?wcJO9kT4o3IC!t0yU|C^%*&t6jNMBd|N5)uMp^VI;v z`hR4ydo9z=+Ul!PyUijKQu7Th(keZdWeB97MaHf%bW)Al7yUZ_7(B6LI=twVtqbaT z2XYRSa?RU5>gdQ({nT;asK&!7N#m1?X2<2E32c;nc&D}-@oMwk!HeLPZ_%-LYW4i; zXFA@z#QkS3`439*wD*=5)mL5EZ+{d+cQd#4vy7@OLi$V)ri|?a7mR0VU^6(En&WI= zHI%!|3vp&2e_IYP)2f4v%EaCINx{%*)w_tcRP%ie)CP=eTdJsNo>o5eX4l9jKa7Ii zM|mz$3;-t4Mkg%@d+`L7aj|T)ESxynMQ0s_55XF~GpduJ#gm!>-@w_HQ>BP8oWT@Z z9Ys38CJc-92V3fmNvkK>!L1JULr=PC_{!!-X`^!sxsJ%x_l{I5TNE4NaFw3<6}WgL zHQ*G9BF%HI6xweL*lP&xB##E8dT;a0)QnKEX@RG@W{)Dhb~+PgQ7#c8)%dX2MM0~M z=-PVBrPH#2X1_r}uNgdfmpqvR*Zc1&d933u=$a?xx5iqEsYuZ10a;vqu(5MLoPqC8 zJ$zVOt+;N*^TiNm7;e+Uscs^JEmLV3#q#+8Y&|FK5w9Bl239h}UK9gzoy-}(!nL99LS zcYiib&_;l67ZO$v@oDq+vrjb;Ff}9yTH!Av(H;LLFPif%m}JS0l37FzegyE@b5{{wiGi@#u+h=Ls>@D-D&cBxz6E z?}kX^r68d&q5rdY@AZma0}bLx@OS&?zWodK_g=o=$-g7pkNWleC+we`eSb0hyPNK} z-|iprd*JTZ?mygjf0g>%Kln$^@AkLdn6_Xkt9pX>j~^Ot+?pXcyjmG8IA{v*&JUS7~&KVJ98~E~M9oH8cc7!|%-j@&5q4eah+p literal 0 HcmV?d00001 diff --git a/server/src/main/java/com/lona/tictactoe/server/GameInstance.java b/server/src/main/java/com/lona/tictactoe/server/GameInstance.java index c5b52b7..aa806fe 100644 --- a/server/src/main/java/com/lona/tictactoe/server/GameInstance.java +++ b/server/src/main/java/com/lona/tictactoe/server/GameInstance.java @@ -55,6 +55,7 @@ public class GameInstance { if (checkWin(symbol)) { finished = true; + lastWinner = symbol; broadcast("WIN " + symbol); } else if (checkDraw()) { finished = true; @@ -72,13 +73,32 @@ public class GameInstance { char loser = (player == playerX) ? 'X' : 'O'; char winner = (loser == 'X') ? 'O' : 'X'; broadcast("WIN " + winner + " (Surrender)"); + lastWinner = winner; } + private char lastWinner = ' '; + public synchronized void restart() { + // Determine who starts: The loser of the previous game. + // If lastWinner was 'X', then 'O' (the loser) starts. + // If lastWinner was 'O', then 'X' (the loser) starts. + // If it was a draw or new game, default to 'X'. + + if (lastWinner == 'X') { + currentTurn = 'O'; + } else if (lastWinner == 'O') { + currentTurn = 'X'; + } else { + currentTurn = 'X'; // Default for Draw/New + } + + lastWinner = ' '; // Reset for next game + finished = false; + + // Clear board for (char[] row : board) Arrays.fill(row, ' '); - currentTurn = 'X'; - finished = false; + broadcast("RESTART"); sendBoard(); broadcast("TURN " + currentTurn); diff --git a/server/target/classes/com/lona/tictactoe/server/GameInstance.class b/server/target/classes/com/lona/tictactoe/server/GameInstance.class index 90d6e32f4a8b5c4502a34ced513229ac1ca282e3..5c4a86e3620084899102c8b7c974e03382a64afe 100644 GIT binary patch literal 4363 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 be1DHX-jttj%g=Z4OO6ECdx6RO2-W`s5Pyg% literal 4238 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 Sk0E;vdPIU6m_J3CQ~4K;Zzrz+ delta 2746 zcmZ9Odpy(oAIDvi8A=!?n{DP&63eAh?$_KoHZLVm~?~^iMwy?G<<4vYIM}l^bjfgg1S88L_C-_9muiEd90s^l-axJrb zeGK}VU9m^~g$o8|I)^X2v5}TKznoO_OB9-wWzOZJI`wSKqxwhVCgLWzDHB|?$Q6qI znepw7>cv$cM6K1}E^A*a@=AT|tEgV+cN)Rw4K0F=m79p1(_=bYH5y}Tkk4Md^=_5% zEQ%gT@XoG$2~BF(i{$2;48LfxXVYIYGCr0YRxoVXZKJpJTkOq4_kvuuW{RO<_?1j8gHYqu>XV0J;TfS+0jw21!^Ya+F=|zi7o`E0ms z|3Z{$!ubm-nlHZN*N|% z%~2a3Y0Dp@-q|VH^ZR?|FedO?NO|6rf!XqobCj;zQe4p-`=p+D)W16QUB?8<%Ui)Nc ztJQ=XV`Y8M#}Q*w-^JVKe=M)pKN332mg$oJyb(0ebR+Glcd7I^G`H@@feokLTfX$X zP}PU7bJ)BA;$n6af;m`_#9RJDz1cKc8kTa6tmt|*yveB>U%|A?Vp{z8x{=Cq9HEB6 zk2DB|`zPfkrJa}FoOM&IIojO(3{garu9AInYVNM{OAPcu2Y9&Ndh%yR?=?<6wtJ*p zS@M2}z+tG!ui3W**SJwwYDmc(6f8|7w^ z>jQ1?%yd-ZRYvc6efpjS-$og*UP>eM>+O#>x2kgYJJk9p$efjYYKrq`ouOb&>7+*S z?k0bv@#7O{bcG>Uf_8hl7<~Mu)cvegvf}AA(r@zf&^uByV2NkhInn zv34)cO`L0<8)xIVm5>Y;*JyGh2Vum}*NU+|meoPdRBB0Y4qNGz_14NfDCb;rCdiev zAp2Hx^I|iLz#JP4N~$&SrUpJQCD1DaVACtp^J}-7rb8V4+E+&t7L{zX`q3D&*foz) zTvho-0_wrD?WlLQEm0fs{{fFCyKxf4T z4|dAl!_BHI$Ag@Y`z7Tj(|%6iY8za)}7;_BP_E9JD$you$D+g{pquMBi= z`fXJTHK@=F!tSI~>3bdak~5?BGD0Q(e0VT9yEJQ{Yhbs9Z8c^Yj}aJSkX{3g)L8cf zf7Q==P%4&^>wA?x4>r{|48QLf_~3%{2}u>+fo~-96sYlp3%@|^v>TW_JgDFUigbKh zn4=uZEKzCtVrA`KsDg0wDlK8V@(K20_>xQ?0wKCR_4e2niXGaa+13liRTajk~Nk+{iVvCrCi`d2fGFN5#h3n6|=CFXm-i!gwX5Q0kHWCgVZj> zg5b&ByJ|^2K0kkxZ@W<{xxH=;c`CI4PC4+nt7Is+hIBE}!LO++_gdq-2HY-egZj0n z0qIYbGvcoQ#WgxDuWoMsh4M3m{}uXh^|F_;D<8B{?w$B{pT_1(WXSvTB? zC;HfMoL1If@10#anSinUwZ>q{reQYjP2hE$W!eAC)}8 z9bJmp6%5tCv?L##_FSV8>{{()|GMeex2cq2`rX6Mf~@^SG}Vdl*p3-PJ33({J*GH$ZbtcN z!KB_z7wVy;KzO|=VG(#gEl&CBu?cVg477pgH*ZI)6negA9oGkKj4x-FtlG76sFNg4 zwe9y8B;|&eGb^I6jlUjEqAa)fTeo+v_E!JQyy`UK>#}O^)jr`+h4R4mnC)-->OVNQ)Rl*`tu&Z9!RcDx6#rMPKq6cs%}}}yyyZ}|3CQ#|VX{=U#Km|- z;3G^|7)o&St)SuHF=8OzmSUNfMdN{&h)4+o<^dy5;4l&^>?%MS3q7n0X(O_3~*G{0E&jX z@QFqZHL-Ze7C``u8Y)5pLaT}SsBRIx9Uji2Vv6GbS|bpQRud%ysc5)x#G6}f^)P^? zi3X<7GD5PrMfgIZ3w%P!05+O%F+=#)ReygX;q-r>0&NNCKmR6ejTFDN5B|@50l-sD Kr|oE@5dID1j1kQM diff --git a/server/target/server-1.0-SNAPSHOT.jar b/server/target/server-1.0-SNAPSHOT.jar index ba142348e4d4c29c038e4bcbc8247c383b8c91cc..c46933b826fe2f7c39874e3429145c17fe59916a 100644 GIT binary patch delta 2806 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 diff --git a/web-client/src/main/java/com/lona/tictactoe/web/TcpSession.java b/web-client/src/main/java/com/lona/tictactoe/web/TcpSession.java index 39efa55..9c13fa8 100644 --- a/web-client/src/main/java/com/lona/tictactoe/web/TcpSession.java +++ b/web-client/src/main/java/com/lona/tictactoe/web/TcpSession.java @@ -30,9 +30,11 @@ public class TcpSession extends Thread { @Override public void run() { try { + System.out.println("TcpSession: Connecting to " + host + ":" + port); socket = new Socket(host, port); out = new PrintWriter(socket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + System.out.println("TcpSession: Connected successfully"); // Flush queue String queued; @@ -46,8 +48,16 @@ public class TcpSession extends Thread { session.sendMessage(new TextMessage(line)); } } + } catch (java.net.ConnectException ce) { + System.err.println("TcpSession: Failed to connect to game server: " + ce.getMessage()); + } catch (java.net.SocketException se) { + if (running) { + // Only print if we didn't initiate the close + System.err.println("TcpSession: Socket closed unexpectedly: " + se.getMessage()); + se.printStackTrace(); + } } catch (IOException e) { - // connection lost or failed + System.err.println("TcpSession: IO Error: " + e.getMessage()); e.printStackTrace(); } finally { close(); diff --git a/web-client/target/classes/com/lona/tictactoe/web/TcpSession.class b/web-client/target/classes/com/lona/tictactoe/web/TcpSession.class index 95f37143c117a0b43b4062a47eca7957c0e86744..aa89f8e51ffdecf2e68b69486d145cf2b25d320b 100644 GIT binary patch literal 3960 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 diff --git a/web-client/target/web-client-1.0-SNAPSHOT.jar b/web-client/target/web-client-1.0-SNAPSHOT.jar index 3890a4099e3e064e1d4b9a87e81060556a28e94a..7d7de80160568f68a4a1f8a6231b640046aeea7e 100644 GIT binary patch delta 5884 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 S+tRwfahb|OrgmIh{r>}2m}^V` diff --git a/web-client/target/web-client-1.0-SNAPSHOT.jar.original b/web-client/target/web-client-1.0-SNAPSHOT.jar.original index 9cff0d9201495c69b6893ddc4d213cd3457b3e0d..957ff94784cd7c65ddcd59b3e27e8eac379531cf 100644 GIT binary patch delta 2516 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 Q{=w7cB(F0{i2