Contents
Outline
TwistGame is a fantastic board game, which involves the board, pegs, and pieces. Different challenges are identified by different initial positions of the pegs or pieces. The player wins after the objective of challenge has been achieved. This is my postgraduate project from October, 2018 to September, 2018.
Demo
UI:
![](https://img-blog.csdnimg.cn/20200730224326188.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZHlsZWxl,size_16,color_FFFFFF,t_70)
Game process: (left to right)
![](https://img-blog.csdnimg.cn/20200730224356534.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZHlsZWxl,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200730224405640.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZHlsZWxl,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200730224414325.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZHlsZWxl,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200730224422574.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZHlsZWxl,size_16,color_FFFFFF,t_70)
Introduction
Components
Board
The game is played on a board comprised of 32 locations arranged in an 8x4 grid. In the plastic game, each location consists of a circular depression in the plastic into which a piece may fit, and in the centre of the depression is a hole (well) into which a peg may be inserted at the start of the game, to form part of the challenge. Locations are encoded as a digit (1 to 8) followed by a letter (A to D). For example, in the game above, the green peg is in position 3C and the red peg is in position 6B.
Pieces
The game comprises 8 playing shapes, each of which is made of plastic and consists of three, four, or five connected loops (see the photo above). The pieces fit neatly into the depressions on the board formed by the 32 locations. Each of the loops is either filled or has a hole. In the game above, the blue piece at the left has four loops, three of which are filled and one of which has a hole. When pieces are placed, the location and orientation must be chosen such that loops that are filled are not placed on locations that contain pegs. In the game above, for example, in the first step, a blue piece placed is carefully positioned so that one of its holes fits over the blue peg at location 2B. Each piece can be flipped and rotated at 90 degree increments, allowing for 8 different orientations (four rotations and a flip with four rotations). The following illustration shows all 64 possible combinations of the 8 pieces and 8 orientations. The first four columns show four rotations. The piece is then flipped and rotated four more times. So the fifth image in the top row (a4) illustrates the flip of the left-most image (a0).
Strict Symmetry
Notice that piece c and piece h are symmetric, so the flipped orientations are identical to the unflipped (for example c0 is
identical to c4, and h0 is identical to h4). We describe that as ‘strictly symmetric’. We ignore the redundant rotations
with higher numberings (e.g. c4 is ignored because it is redundant with respect to c0 and has a higher rotation number).
Weak Symmetry
Notice that if we ignore the holes, aside from a, d and g, all pieces exhibit symmetry. We describe these as ‘weakly
symmetric’, and thus take up exactly the same space on the board. We ignore the redundant rotations with higher numberings (e.g.
if a solution could be made with either e0 or e7 then we ignore the solution with e7 because it is weakly symmetric and has a higher rotation number). Other examples include b0 & b2, c0 & c2, f0 & f6, and h0 & h2, each of which are identical pairs if we ignore the holes.
Pegs
The game has seven pegs. There are two green, two blue and two yellow pegs, but just one red peg. The pegs are not placed by the player during the game, but rather, one or more pegs is placed on the board at the start of the game as part of the challenge. In the example above, two blue, two yellow, one green and one red peg are placed to form the challenge, as well as a green piece. The player has to place the remaining pieces. The particular challenge illustrated above is challenge one in the booklet that comes with the IQ-Twist game.
Objective
The objective is to place all eight coloured playing pieces onto a board comprising 32 locations(4*8) (indents) on which up to seven coloured pegs may be arranged. The player must place the pieces such that they fit together correctly on the board, without overlaps or gaps. Also, each of the pegs must be surrounded by a piece of the same colour, meaning the piece must have a hole in the necessary place.
In the photo above, a blue peg at upper right is surrounded by a blue piece, with the peg fitting exactly into a hole in the blue piece. The player will need to place the green and red pieces so that they fit neatly on the green and red pegs, and to complete the game will need to ensure that all pieces are placed with no overlaps and no gaps.
A completed game:
Challenges
A game starts with a challenge which involves zero or one pieces and one or more pegs being placed. Here is what the game above starts like, ready to be solved (this happens to be challenge 1 that comes with the game). Notice that this particular challenge starts with one piece placed and six pegs placed :
Note that the more constrained the player is, the fewer options they have, and consequently the solution to the challenge is, in general, simpler: For example, many of the ‘Wizard’ level challenges that come with the game (e.g. numbers 118-120) have just three pegs placed, which leaves the player with a large number of placements to choose from, and thus creates a much more challenging game. On the other hand, some of the ‘Starter’ challenges (e.g. number 17) have all seven pegs and one piece placed, significantly reducing the player’s options and consequently making the challenge far easier.
Solutions
Each challenge has just one solution. When comparing solutions, we ignore piece rotations that take up the same space on the board. Such rotations are described as symmetric, which is defined in more detail below. The following sequence shows one possible progression of a solution to the game above (note that the order in which the pieces are played is not important; this is just one possible ordering).
Placement Strings
Legal Piece Placements
For a piece placement to be valid, the following must be true:
- All loops comprising each piece must be placed on valid board locations (no part of a piece may be off the board).
- All loops comprising each piece must be placed on vacant board locations (pieces may not overlap).
- No piece may be placed over a peg, except where the peg is the same color and the location of the peg coincides with a loop that has a hole. For example, in the game above, the blue piece at the left is placed such that it fits on the peg at location 1C.
Encoding Game State
Game states are encoded as strings. Your game will need to be able to initialize itself using these strings and some of your tasks relate directly to these strings.
Placement Strings
A placement string consists of between one and eight (inclusive) piece placements (pieces a to h), and between zero and seven peg placements. The placement string may not include any piece twice, and may not include more pegs than are available. A completed game must include eight piece placements. Each piece placement is described using four characters.
For example, the game described above is characterized (when complete) by the string a7A7b6A7c1A3d2A6e2C3f3C4g4A7
h6D0i6B0j2B0j1C0k3C0l4B0l5C0. Note that the placement string is ordered (piece a first, and piece l last), which is a requirement for valid placement strings.
Piece Placement Strings
A piece placement string consists of four characters describing the location and orientation of one particular piece on the board:
The first character identifies which of the eight shapes is being placed (a to h).
The second character identifies which column the left of the piece is in (columns are labelled 1 to 8).
The third character identifies which row the top of the piece is in (rows are labelled A to D).
The fourth character identifies which orientation the piece is in (0 to 3 for four rotations, and then 4 to 7 for four flipped rotations).
The image above shows the first and fourth characters for each of the pieces in each of their orientations (64 in total).
For example, at top left, ‘a0’ describes piece ‘a’ at orientation ‘0’. Below it, ‘b0’ describes piece ‘b’ at orientation ‘0’.
At the bottom right ‘h7’ describes piece ‘h’ at orientation ‘7’. And so on. A piece placement string starts and ends with these two characters and has two more in between which describe where the piece is placed.
Peg Placement Strings
Peg placement strings follow exactly the same format as piece placement strings, however, pegs use the characters i (red), j
(blue), k (green), and l (yellow), and the rotation is always 0 for a peg placement, since it makes no sense to rotate a peg, which is round.
Example Placement String
The progression of twelve images above shows the progression of the game a7A7b6A7c1A3d2A6e2C3f3C4g4A7h6D0i6B0
j1C0k3C0l4B0l5C0, starting with the starting state f3C4i6B0j2B0j1C0k3C0l4B0l5C0, then adding piece d with its left in column 2, its top in row A, and rotated and flipped to rotation 6, which is encoded as a piece placement of d2A6. The resulting placement string is d2A6f3C4i6B0j2B0j1C0k3C0l4B0l5C0, etc.
Design Summary
There are 8 classes in this project:
GUI classes: Board, Peg, Piece, Shape, Music.
Logic classes: Loop, PieceIni, TwistGame.
Class Design
Peg
Main Idea: This class repesents the 4 different pegs.
Main Function: checkPeg(char name,char colum,char roww);
Explanation: This function can place correct peg to the board if given the name,column,row of this peg.
public static void checkPeg(char name,char colum,char roww)
{
/*change the size of peg i and put it to the right place*/
int row = roww -'A';
int column = colum -'1';
ImageView tmp = new ImageView();
tmp.setImage(new Image(Board.Peg_URLs[name-'i']));
double width = tmp.getImage().getWidth();
double height = tmp.getImage().getHeight();
double col = column*40 - 0.3*width + 80;
double ro = row*40 - 0.3*height + 120;
tmp.setX(col);
tmp.setY(ro);
tmp.setScaleY(0.4);
tmp.setScaleX(0.4);
controlpeg.getChildren().add(tmp);
// public static final Group controlpeg = new Group();
}
Piece
Main Idea: This class helps to drag and rotate the pieces in the board.
Main Function: iniboardpiece(String pegpiece);
Explanation: Initialize pieces of board and use mathmetical method to solve the rotate or flip problem.
1. Scroll(rotate and flip)
shapesTmp.setOnScroll(event -> {
mouseX = event.getSceneX();
mouseY = event.getSceneY();
event.consume();//destroy instance
if (PlacedRotation[x - 'a'] != -1)//x is piece name
rotateCount = PlacedRotation[x - 'a'];//the Count of rotation
rotateCount++;//scroll one more time
PlacedRotation[x - 'a'] = rotateCount;//update the number of rotation
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (rotateCount % 8 <= 3) {//rotateCount = 1,2,3
shapesTmp.setScaleY(0.4);
shapesTmp.setRotate((shapesTmp.getRotate() + 90) % 360);
} else {
shapesTmp.setScaleY(-0.4);//rotateCount = 4,5,6,7
shapesTmp.setRotate((shapesTmp.getRotate() + 90) % 360);
}
});
2. Dragged
shapesTmp.setOnMouseDragged(event -> { // mouse is being dragged
double movementX = event.getSceneX() - mouseX;
double movementY = event.getSceneY() - mouseY;
shapesTmp.setLayoutX(shapesTmp.getLayoutX() + movementX);
shapesTmp.setLayoutY(shapesTmp.getLayoutY() + movementY);
shapesTmp.toFront();
mouseX = event.getSceneX();
mouseY = event.getSceneY();
event.consume();
});
3. DragDetected
shapesTmp.setOnDragDetected(event -> {
mouseStartX = mouseX;
mouseStartY = mouseY;
});
4. MousePressed
shapesTmp.setOnMousePressed(event -> {//used to record final place of mouse
mouseX = event.getSceneX();
mouseY = event.getSceneY();
event.consume();
});
5. MouseReleased
- Locate the place where the piece should be put and record the rotation times
finalX = mouseX;
finalY = mouseY;
double moveX = finalX - mouseStartX;
double moveY = finalY - mouseStartY;
double finalvertex_X;//the place where the piece should be put
double finalvertex_Y;
if (rotateCount % 2 == 1) {
finalvertex_X = column * 40 + moveX + Math.abs(0.5 * 0.4 * (height - width));
finalvertex_Y = roww * 40 + moveY - Math.abs(0.5 * 0.4 * (height - width));
} else {
finalvertex_X = column * 40 + moveX;
finalvertex_Y = roww * 40 + moveY;
}
- The small Circle is used to help locate the piece
c = new Circle(finalvertex_X, finalvertex_Y, 0.5);
c.setOpacity(50);
c.setFill(Color.WHITE);
iniboardpiece.getChildren().add(c);
/*used to test whether the placement of piece is true*/
Circle tmpc = findNearestNode(findNearestDistance(finalvertex_X, finalvertex_Y), finalvertex_X, finalvertex_Y);
int v_x = (int) (tmpc.getCenterX() - 80) / 40 + 1;
int v_y = (int) (tmpc.getCenterY() - 120) / 40;
char c_vy = (char) (v_y + 'A');
if (rotateCount % 2 == 1) {
shapesTmp.setLayoutX(tmpc.getCenterX() - column * 40 - Math.abs(0.5 * 0.4 * (height - width)));//+ Math.abs(0.5*0.4*(height-width)
shapesTmp.setLayoutY(tmpc.getCenterY() - roww * 40 + Math.abs(0.5 * 0.4 * (height - width)));//- Math.abs(0.5*0.4*(height-width)
} else {
shapesTmp.setLayoutX(tmpc.getCenterX() - column * 40);
shapesTmp.setLayoutY(tmpc.getCenterY() - roww * 40);
}
stmp = x + "" + v_x + "" + c_vy + "" + (rotateCount % 8);//a very important string
- Try to insert the new piece to the place where the mouse is pointing
List<Character> list = new ArrayList<>();
List<Character> listofPieces = new ArrayList<>();
if (validString.length() > 0) {
String lpeg = new String();
lpeg = pegpiece + validString.toString();
validString.replace(0, validString.length(), "");//update the valid string
/*add peg to the valid string*/
TreeSet<String> ts = new TreeSet<>();
for (int k = 0; k < lpeg.length() / 4; k++) {
String str = lpeg.substring(k * 4, (k + 1) * 4);
ts.add(str);
}
String validstr = "";
for (String s : ts) {
validstr += s;
}
validString.append(validstr);
} else validString.append(pegpiece);
for (char c : validString.toString().toCharArray()) {
list.add(c);
}
for (char c : pegpiece.toCharArray()) {
if (c >= 'a' && c <= 'h') {
listofPieces.add(c);
}
}
int insertPos = 0;
int count = 0;
//find the position of character which before x
for (int q = 1; q < 8; q++) {
int indexc = list.indexOf((char) (x - q));
if (indexc != -1 && count == 0) {
insertPos = indexc + 4;
count++;
}
}
validString.insert(insertPos, stmp);//prepare to insert
- Test whether the string is valid after inserting this new piece, if this piece is not valid ,show an wrong message and remove the string of this piece from validString
if (isPlacementStringValid(stmp)) {
if (!isPlacementStringValid(validString.toString())) {//in the board but not in right place
Music.PutfailMusic();
validString.replace(insertPos, insertPos + 4, "");
PlacedRotation[x - 'a'] = rotateCount;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
shapesTmp.setLayoutX(0);
shapesTmp.setLayoutY(0);
} else {//place successfully
Music.PutsuccessMusic();
}
} else {
Music.PutfailMusic();
System.out.println("fail to place ,out of board!!");
validString.replace(insertPos, insertPos + 4, "");
PlacedRotation[x - 'a'] = rotateCount;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
shapesTmp.setLayoutX(0);
shapesTmp.setLayoutY(0);
}
- Place the piece successfully
if (validString.length() >= 32) {
if (checkSuccess(validString.toString().substring(0, 32))) {
place[x-'a'] = true;
Label success = new Label();//"congratulations,successful!!"
Image finish = new Image((Board.succ_URL));
success.setGraphic(new ImageView((finish)));
success.setLayoutX(160);
success.setLayoutY(160);
Music.playSuccessMusic();
iniboardpiece.getChildren().addAll(success);
}
}
subs = validString.toString();
int pegPos = 0;
int countPeg = 0;
int piecePos = 0;
- Remove the peg string from validString
List<Character> list1 = new ArrayList<>();
for (char c : validString.toString().toCharArray()) {
list1.add(c);
}
for (Character c : list) {
if (countPeg == 0 && c >= 'i' && c <= 'l') {
pegPos = list1.indexOf(c);
countPeg++;
}
}
validString.replace(pegPos, validString.length(), "");
for (Character c : listofPieces) {
//c is redundant piece, c should be remove
piecePos = validString.toString().indexOf(c);
if (piecePos != -1)
validString.replace(piecePos, piecePos + 4, "");
}
/*check whether the valid string is finished,if finished, show successful message*/
rotateCount = 0;
});
Shape
Main Idea: This class repesents the 8 different shapes
Main Function: checkShape(char name,int column,int row,int orientation);
Explanation: This function can place correct shape to the board if given the name,column,row,and orientation of this shape
public static void checkShape(char name, char colum, char roww, int orientation, int tag) {
int row = roww-'A';
int column = colum -'1';
int na = name -'a';
ImageView tmp = new ImageView();
tmp.setImage(new Image(Board.URLs[na]));
tmp.setScaleX(0.4);
double width = tmp.getImage().getWidth();
double height = tmp.getImage().getHeight();
double col = column*40 - 0.3*width + 80;
double ro = row*40 - 0.3*height + 120;
if(orientation %2 ==1 )
{
col = col - Math.abs(0.5*0.4*(height-width)) ;
ro = ro + Math.abs(0.5*0.4*(height-width));
}
if (orientation < 4) {
tmp.setScaleY(0.4);
tmp.setX(col);
tmp.setY(ro);
tmp.setRotate(orientation * 90);
} else if(orientation >= 4){
tmp.setX(col);
tmp.setY(ro);
tmp.setRotate(orientation * 90);
tmp.setScaleY(-0.4);
}
if (tag == 0){
controlshapes.getChildren().addAll(tmp);
}else {
tmp.setOpacity(0.5);
controlshapes.getChildren().addAll(tmp);
}
}
Music
Main Idea: This class contain 3 different musics this game will use.
- Success
- Fail to put pieces
- Put pieces successfully
private static final String URL_BASE = "assets/";
private static final String m_URL = Board.class.getResource(URL_BASE + "start.mp3").toString();
private static AudioClip start = new AudioClip(m_URL);
public static void playStartMusic() {
start.play();
}
Loop
Main Idea: This class repesents the loop which has two attributes x and y and then uses 2 arraylists to store all the loops or depressions of each piec
Take Arraylist that stores the data of depressions as an example:
/*each piece has depressions*/
static int[] aDep = {0,2};
static int[] bDep = {2};
static int[] cDep = {1};
static int[] dDep = {2,4};
static int[] eDep = {1,2};
static int[] fDep = {2,3};
static int[] gDep = {0,1,3};
static int[] hDep = {0};
static List<int[]>piecedeps = new ArrayList<>();//arraylist to store all the depressions of each piece
static void iniPieceDep() {//add nodes to the piecedeps
piecedeps.add(aDep);
piecedeps.add(bDep);
piecedeps.add(cDep);
piecedeps.add(dDep);
piecedeps.add(eDep);
piecedeps.add(fDep);
piecedeps.add(gDep);
piecedeps.add(hDep);
}
PieceIni
Main Idea: This class realizes the rotation and flip of shapes
public class PiecesIni{
/*initialize all the first shape of 8 pieces like a0,b0,c0,d0,e0,f0,g0,h0 and their depression placement*/
static void IniLoopAndDepress()
{
Loop.iniPieceDep();
Loop.iniPieceLoop();
}
/*loop[] means a loops of each piece ,and every piece can be rotated to specific degree
* when rotateTime is 0,it means the first shape of this piece
* one rotateTime means 90 degree rotation
* rotateTime = 1,2,3 means a1,a2,a3
* this function includes some mathmetical transformations
*/
static Loop[] rotate(Loop[] shape,int rotateTime)//totate-->1 90
{
Loop[] shaperotate = new Loop[shape.length];
int max = shape[0].y;
for (int i = 0; i < shape.length; i++) {
if (shape[i].y > max) {
max = shape[i].y;
}
}
for (int i = 0; i < shape.length; i++) {
shaperotate[i] = new Loop(0,0);
shaperotate[i].x = shape[i].y * (-1) + max + 1;
shaperotate[i].y = shape[i].x;
}
if (rotateTime == 0) return shape;
else if (rotateTime == 1) return shaperotate;
else return rotate(shaperotate, rotateTime - 1);
}
/*
* every piece can be flipped when given specific fliptime
* fliptime = 1,2,3,4 means a4,a5,a6,a7
*/
static Loop[] flip(Loop[] shape,int flipTime)//
{
Loop[] shapeflip = new Loop[shape.length] ;
int max = shape[0].y;
for (int i = 0; i < shape.length; i++) {
if (shape[i].y > max) {
max = shape[i].y;
}
}
for (int i = 0; i < shape.length; i++) {
shapeflip[i] = new Loop(0, 0);
shapeflip[i].x = shape[i].x;
shapeflip[i].y = shape[i].y * (-1) + max + 1;
}
if (flipTime == 1) return shapeflip;
else return rotate(shapeflip, flipTime - 1);
}
}
TwistGame
Main Idea: This class provides the interface for the Twist Game
Some functions:
public static boolean isPlacementWellFormed(String piecePlacement);//determine whether a piece or peg placement is well-formed
public static boolean isPlacementStringWellFormed(String placement);//determine whether a placement is well-formed
public static boolean isPlacementStringValid(String placement); // determine whether a placement string is valid
public static Set<String> getViablePiecePlacements(String placement);//determine the set of valid next piece placements
Two important functions: getSolutions and InsertOfList
Main Idea: Since we can use fuction:getViablePiecePlacements() to get all the viable set of string, for example, if we get viable set like this: a1A0,a1C0,b1D2,b2C2,c2B1,c3B1. we will check whether these strings are valid:
a1A0b1D2c2B1,a1A0b1D2c3B1,a1A0b2C2c2B1,a1A0b2C2c3B1,
a1C0b1D2c2B1,a1C0b1D2c3B1,a1C0b2C2c3B1,a1C0b2C2c2B1. so in order to find the right place to insert, I design a function named: insertOfList().
getSolutions:
For example, if we get viable set like this: a1A0,a1C4,b1D5,b2C8, we will check whether these strings are valid: a1A0b1D5,a1A0b2C8,a1C4b1D5,a1C4b2C8.
public static String[] getSolutions(String placement) {
/* the tree order of all solution strings(a1A0,a1C4,b1D5,b2C8),
* the start character of all solution strings(a,a,a,a,b,b,b,b,b)*/
TreeSet<String> placeTreeSet = new TreeSet<>();
/* in order to calculate the amount of different characters(a,b,c,d)
* valueset stores the first character of all these viable strings (like a,b,c,no duplicates)*/
Set<Character> valueset = new HashSet<>();
List<TreeSet<String>> treeSetlist = new ArrayList<>();//all treesets
//the value of each map is the first character of this string
Map<String, Character> smap = new HashMap<>();
//all possible solutions:(a1A0,b1D5,a1C4,b2C8)
Set<String> placementSet = getViablePiecePlacements(placement);
//change placement into the stringbuffer,it will be convenient for us to operate
StringBuffer validString = new StringBuffer();
List<String> l = new ArrayList<>();//store the results of this function
TreeSet<String> TreeSetOfs;
for (String s : placementSet) { //all the viable string of pieces
placeTreeSet.add(s);
}
for (String s : placeTreeSet) {
//string as the key ,the first character of this string as the value,put them into the map
smap.put(s, s.charAt(0));
valueset.add(s.charAt(0));
}
/* use different treesets to store the viable string of each piece
* just like we get viable pieces like this: a1A0,b1D5,a1C4,b2C8
* then we can get:
* treeSetlist.get(0) :a1A0a1C4 and
* treeSetlist.get(1) :b1D5b2C8
*/
for (Character s : valueset) {
int i = 0;
TreeSetOfs = new TreeSet<>();
for (Map.Entry<String, Character> entry : smap.entrySet()) {
if (entry.getValue().equals(s)) {
TreeSetOfs.add(entry.getKey());
}
}
treeSetlist.add(TreeSetOfs);
i++;
}
for (char p : placement.toCharArray()) {
validString.append(p);
}
// the most important part:recursive
insertOfList(valueset.size() - 1, treeSetlist, validString, l);
String[] sus = new String[l.size()]; //change list into String[]
for (int i = 0; i < l.size(); i++) {
sus[i] = l.get(i);
}
return sus;
}
insertOfList: try to find all possible placements of given viable strings
//
static void insertOfList(int n, List<TreeSet<String>> treeSetlist, StringBuffer validString, List<String> l) {
if (n >= 0) {
for (String s : treeSetlist.get(n)) {
int insertPos = 0;
int count = 0;
/*
find the character which is the fisrt character smaller than s.charAt(0)(like b of b1D5),
we will find a in the existed placement, then we can insert b1D5 to the position of a plus 4
if this character element does not exist,the position of inserting this piece(b1D5) will be 0
*/
for (int q = 1; q < 8; q++) {
int indexc = validString.toString().indexOf((char) (s.charAt(0) - q));
if (indexc != -1 && count == 0) {
insertPos = indexc + 4;
count++;
}
}
validString.insert(insertPos, s);
insertOfList(n - 1, treeSetlist, validString, l);//recursive
//if all the pieces have been put to the string,we need to check whether this string placement is valid
if (n == 0 && isPlacementStringValid(validString.toString())) {
if (isPlacementStringValid(validString.toString().substring(0, 32)))
l.add(validString.toString().substring(0, 32));
}
//we need to remove this piece in order to put other placement of this piece to the string
validString.replace(insertPos, insertPos + 4, "");
}
}
}
Conclusion
This was a big assignment of the ANU comp6710 course. The Lecturer provided us with a game pattern based on Twistgame, that is, the content mentioned in the introduction part and the test codes of some game logics. In this project, to write all codes except the test codes from scratch, I mastered a lot of java programming skills and theoretical knowledge. This project mainly contained 8 classes, and the most complex one was the Twistgame class that called other classes to achieve the whole UI and game logic.
In the process of game design, I encountered with many problems. Taking the operation on each piece for example, how to correctly decide where the piece should be placed was particularly important when I put the piece on the left board after rotating the piece from the toolbar on the right. To solve this problem, I created a virtual board containing 8*4 circles according to the board structure. Every time when the piece is dragged and placed, the code will calculate the distance between the coordinate where it is dragged and the circles so as to select the nearest circle as a fixed point to place the piece on the board. For piece rotation, the rules of coordinate changes when different pieces rotated should be found according to corresponding mathematical formulas.
The most difficult function to achieve is to get game hints, which was relating to recursion. A poor design will consume a great deal of computer resources. Thus, as summarized in the article, I designed an insertOfList function that mainly took charge of recursive to find all possible placements of given viable strings.