Skip to content

Commit 773b53d

Browse files
committed
Initial commit
0 parents  commit 773b53d

27 files changed

Lines changed: 1835 additions & 0 deletions

File tree

Spaghetti GUI Application.iml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<module type="JAVA_MODULE" version="4">
3+
<component name="NewModuleRootManager" inherit-compiler-output="true">
4+
<exclude-output />
5+
<content url="file://$MODULE_DIR$">
6+
<sourceFolder url="file://$MODULE_DIR$/game" isTestSource="false" />
7+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
8+
<sourceFolder url="file://$MODULE_DIR$/swing" isTestSource="false" />
9+
</content>
10+
<orderEntry type="inheritedJdk" />
11+
<orderEntry type="sourceFolder" forTests="false" />
12+
</component>
13+
</module>

game/game.iml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<module type="JAVA_MODULE" version="4">
3+
<component name="NewModuleRootManager" inherit-compiler-output="true">
4+
<exclude-output />
5+
<content url="file://$MODULE_DIR$">
6+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
7+
</content>
8+
<orderEntry type="inheritedJdk" />
9+
<orderEntry type="sourceFolder" forTests="false" />
10+
<orderEntry type="module" module-name="utils" />
11+
</component>
12+
</module>

game/src/spaghetti/game/Board.java

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
package spaghetti.game;
2+
3+
import spaghetti.utils.Pair;
4+
import spaghetti.utils.Triplet;
5+
6+
import java.util.*;
7+
import java.util.List;
8+
9+
/************************************************************
10+
* The play function is written by Ludo Pulles in javascript
11+
* and is translated to Java.
12+
* https://www.codecup.nl/spaghetti/sample_game.php
13+
***********************************************************/
14+
public class Board {
15+
public static class Position extends Triplet<Integer, Integer, Integer> {
16+
public Position(Integer a, Integer b, Integer c) {
17+
super(a, b, c);
18+
}
19+
20+
@Override
21+
public Position copy() {
22+
return new Position(a, b, c);
23+
}
24+
}
25+
public static class Point extends Pair<Integer, Integer> {
26+
public Point(Integer a, Integer b) {
27+
super(a, b);
28+
}
29+
30+
@Override
31+
public Point copy() {
32+
return new Point(a, b);
33+
}
34+
}
35+
36+
public final int width, height;
37+
public final Tile[][] tiles;
38+
public final int[] scores = {50, 50};
39+
protected final List<BoardListener> listeners = new ArrayList<>();
40+
protected final BoardListener[] controllers = new BoardListener[2];
41+
protected boolean turn = false;
42+
public boolean gameStarted = false;
43+
protected int moveCount = 0;
44+
45+
public Board(int width, int height) {
46+
this.width = width;
47+
this.height = height;
48+
tiles = new Tile[height][width];
49+
for (Tile[] t : tiles) {
50+
for (int i = 0; i < width; ++i) t[i] = new Tile();
51+
}
52+
}
53+
54+
public void addBoardListener(BoardListener l) {
55+
listeners.add(l);
56+
}
57+
58+
public void removeBoardListener(BoardListener l) {
59+
listeners.remove(l);
60+
if (moveCount != 0 && (controllers[0] == l || controllers[1] == l)) close();
61+
}
62+
63+
public void setControllers(BoardListener blue, BoardListener red) {
64+
controllers[0] = blue;
65+
controllers[1] = red;
66+
}
67+
68+
public void swapControllers() {
69+
BoardListener l = controllers[1];
70+
controllers[1] = controllers[0];
71+
controllers[0] = l;
72+
}
73+
74+
public Board(int width, int height, Move[] moves) {
75+
this(width, height);
76+
for (Move m : moves) play(m, null);
77+
}
78+
79+
public void close() {
80+
for (BoardListener l : listeners) l.close();
81+
}
82+
83+
public boolean isRunning() {
84+
return moveCount != width * height;
85+
}
86+
87+
public boolean isGameStarted() {
88+
return gameStarted;
89+
}
90+
91+
public int getMoveCount() {
92+
return moveCount;
93+
}
94+
95+
public boolean getTurn() {
96+
return turn;
97+
}
98+
99+
public BoardListener getControllerTurn() {
100+
return controllers[turn? 1: 0];
101+
}
102+
103+
public boolean isOccupied(int row, int col) {
104+
return tiles[row][col].type != '\0';
105+
}
106+
107+
// sides: 0=N, 1=E, 2=S, 3=W
108+
private static final Map<Character, Integer[]> sides = new HashMap<Character, Integer[]>() {{
109+
put('l', new Integer[]{0, 3, 1, 2});
110+
put('s', new Integer[]{0, 2, 1, 3});
111+
put('r', new Integer[]{3, 2, 1, 0});
112+
}}, nrs = new HashMap<Character, Integer[]>() {{
113+
put('l', new Integer[]{0, 1, 1, 0});
114+
put('s', new Integer[]{0, 1, 0, 1});
115+
put('r', new Integer[]{0, 0, 1, 1});
116+
}}, perm = new HashMap<Character, Integer[]>(){{
117+
put('l', new Integer[]{1, 0, 3, 2});
118+
put('s', new Integer[]{0, 1, 2, 3});
119+
put('r', new Integer[]{3, 2, 1, 0});
120+
}};
121+
122+
private static final int[]
123+
dx = new int[]{1, 0, -1, 0},
124+
dy = new int[]{0, -1, 0, 1};
125+
126+
public boolean inBoard(int row, int col) {
127+
return row >= 0 && row < height && col >= 0 && col < width;
128+
}
129+
130+
private Position stepTile(Position pos) {
131+
int d = perm.get(tiles[pos.a][pos.b].type)[pos.c];
132+
return new Position(pos.a + dx[d], pos.b + dy[d], d);
133+
}
134+
135+
private Pair<Integer, Integer> simulate(Position pos) {
136+
Position p = pos.copy();
137+
int len = 0;
138+
while (inBoard(p.a, p.b) && tiles[p.a][p.b].type != '\0') {
139+
p = stepTile(p);
140+
len++;
141+
if (p.equals(pos)) return new Pair<>(-1, 0); // cycle
142+
}
143+
if (inBoard(p.a, p.b)) return new Pair<>(-2, 0);
144+
145+
if (p.b < 0) return new Pair<>(len, 1);
146+
if (p.b >= width) return new Pair<>(len, 2);
147+
return new Pair<>(0, 5);
148+
}
149+
150+
private boolean visits(Position pos, Position opt1, Position opt2) {
151+
Position p = pos.copy();
152+
while (inBoard(p.a, p.b) && tiles[p.a][p.b].type != '\0') {
153+
p = stepTile(p);
154+
if (p.equals(opt1) || (p.equals(opt2))) return true;
155+
if (p.equals(pos)) return false;
156+
}
157+
return false;
158+
}
159+
160+
private void colorBoth(Position pos0, Position pos1, int color) {
161+
if (color != 5)
162+
color += 2;
163+
Position p = pos0.copy();
164+
boolean cyc = false;
165+
while (inBoard(p.a, p.b) && tiles[p.a][p.b].type != '\0') {
166+
Tile tile = tiles[p.a][p.b];
167+
int n = nrs.get(tile.type)[p.c];
168+
tile.color[n] = color;
169+
170+
p = stepTile(p);
171+
if (p.equals(pos0)) { cyc = true; break; }
172+
}
173+
p = pos1.copy();
174+
if (!cyc) while (inBoard(p.a, p.b) && tiles[p.a][p.b].type != '\0') {
175+
Tile tile = tiles[p.a][p.b];
176+
int n = nrs.get(tile.type)[p.c];
177+
tile.color[n] = color;
178+
179+
p = stepTile(p);
180+
}
181+
}
182+
183+
public void start(boolean prePlayedMoves) {
184+
if (prePlayedMoves && width >= 4 && height >= 4) {
185+
Random rand = new Random();
186+
Move m1 = generatePreMove(rand), m2 = generatePreMove(rand);
187+
System.err.println("Pre Played Moves: " + m1 + ", " + m2);
188+
play(m1, null);
189+
play(m2, null);
190+
}
191+
gameStarted = true;
192+
controllers[0].start();
193+
}
194+
195+
public Move generatePreMove(Random rand) {
196+
Point[] pos = new Point[width * height];
197+
int size = 0;
198+
for (int i = 1; i < height-1; ++i) for (int j = 1; j < width-1; ++j) {
199+
Point p = new Point(i, j);
200+
if (!isOccupied(p.a, p.b))
201+
pos[size++] = p;
202+
}
203+
Point m = pos[rand.nextInt(size)];
204+
char[] t = new char[] {'l', 's', 'r'};
205+
return new Move(m.a, m.b, t[rand.nextInt(3)]);
206+
}
207+
208+
public void play(Move move, BoardListener player) {
209+
moveCount++;
210+
tiles[move.row][move.col].type = move.t;
211+
212+
Position[] pos4 = new Position[4];
213+
for (int i=0; i<4; i++)
214+
pos4[i] = new Position(move.row, move.col, sides.get(move.t)[i]);
215+
216+
for (int i=0; i<2; i++) {
217+
Position pos0 = pos4[2*i], pos1 = pos4[2*i+1];
218+
219+
Pair<Integer, Integer> outcome0 = simulate(pos0), outcome1 = simulate(pos1);
220+
if (outcome0.a == -2 && outcome1.b != 5) continue;
221+
if (outcome1.a == -2 && outcome0.b != 5) continue;
222+
223+
boolean choose_best = i == 0 && (visits(pos0, pos4[2], pos4[3]) || visits(pos1, pos4[2], pos4[3]));
224+
225+
// color: current player
226+
int color = (turn? 2 : 1);
227+
if (outcome0.a == -1 || outcome1.a == -1) {
228+
colorBoth(pos0, pos1, color);
229+
// cycle penalty:
230+
scores[turn? 1: 0] -= 5;
231+
} else if (outcome0.b == 5 || outcome1.b == 5) {
232+
colorBoth(pos0, pos1, 5);
233+
} else if (outcome0.b.equals(outcome1.b)) {
234+
colorBoth(pos0, pos1, color);
235+
// same side penalty:
236+
scores[turn? 1: 0] -= 3;
237+
} else {
238+
if (choose_best) {
239+
int len_01 = outcome0.b == color ? outcome0.a : outcome1.a;
240+
Pair<Integer, Integer> outcome2 = simulate(pos4[2]), outcome3 = simulate(pos4[3]);
241+
242+
int len_23 = outcome2.b == color ? outcome2.a : outcome3.a;
243+
244+
if (len_23 > len_01) {
245+
i = 1;
246+
pos0 = pos4[2];
247+
pos1 = pos4[3];
248+
outcome0 = outcome2;
249+
}
250+
}
251+
252+
// Coloring one half color and other gray
253+
Position p = ((outcome0.b == color) ? pos0 : pos1).copy();
254+
while (inBoard(p.a, p.b)) {
255+
scores[turn? 1: 0]++;
256+
257+
Tile tile = tiles[p.a][p.b];
258+
int n = nrs.get(tile.type)[p.c];
259+
tile.color[n] = color;
260+
p = stepTile(p);
261+
}
262+
Position q = stepTile( (outcome0.b == color) ? pos1 : pos0 );
263+
while (inBoard(q.a, q.b)) {
264+
Tile tile = tiles[q.a][q.b];
265+
int n = nrs.get(tile.type)[q.c];
266+
tile.color[n] = 5;
267+
q = stepTile(q);
268+
}
269+
}
270+
if (choose_best) break;
271+
}
272+
273+
turn = !turn;
274+
for (BoardListener listener : listeners) listener.registerMove(move, player);
275+
}
276+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package spaghetti.game;
2+
3+
public interface BoardListener {
4+
void registerMove(Move m, BoardListener l);
5+
void start();
6+
void close();
7+
boolean isStartHandler();
8+
String getControllerName();
9+
}

game/src/spaghetti/game/Move.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package spaghetti.game;
2+
3+
import java.io.Serializable;
4+
5+
public class Move implements Serializable {
6+
public int row, col;
7+
public char t;
8+
9+
public Move(String str) {
10+
row = str.charAt(0) - 'a';
11+
col = str.charAt(1) - 'a';
12+
t = str.charAt(2);
13+
}
14+
15+
public Move(int row, int col, char t) {
16+
this.row = row;
17+
this.col = col;
18+
this.t = t;
19+
}
20+
21+
@Override
22+
public String toString() {
23+
return "" + ((char)(row + 'a')) + ((char) (col + 'a')) + t;
24+
}
25+
}

game/src/spaghetti/game/Tile.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package spaghetti.game;
2+
3+
import java.awt.*;
4+
5+
public class Tile {
6+
public int[] color = {0, 0};
7+
public char type = '\0';
8+
}

networking/client/client.iml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<module type="JAVA_MODULE" version="4">
3+
<component name="NewModuleRootManager" inherit-compiler-output="true">
4+
<exclude-output />
5+
<content url="file://$MODULE_DIR$">
6+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
7+
</content>
8+
<orderEntry type="inheritedJdk" />
9+
<orderEntry type="sourceFolder" forTests="false" />
10+
<orderEntry type="module" module-name="networking" />
11+
<orderEntry type="module" module-name="game" />
12+
<orderEntry type="module" module-name="utils" />
13+
</component>
14+
</module>

0 commit comments

Comments
 (0)