You are on page 1of 335

FACULTEIT INDUSTRIELE

INGENIEURSWETENSCHAPPEN

TECHNOLOGIECAMPUS GENT

Oplossen Rubik’s Kubus m.b.v


een deltarobot
Bijlage

Pieter DEPAMELAERE
Simon DESCHUYTTER

Promotor(en): ir. K. Bruggeman Masterproef ingediend tot het behalen van de


Ing. R. Claeys graad van master of Science in de industriële
wetenschappen: Elektromechanica

Academiejaar 2015-2016
Inhoudstafel

/CubeThesis
/src
/cbthFileChooser
/CBTHFileChooser .java ............................................. 1
/CBTHFileView .java ................................................ 4
/EigExtFilter .java ................................................ 6
/FileIO .java ...................................................... 7
/ImageFilter .java ................................................ 12
/ImagePreview .java ............................................... 13
/Utils .java ...................................................... 15
/comparators
/IdCBTHSettingComparator .java .................................... 16
/LabelTextCBTHSettingComparator .java ............................. 16
/TypeCBTHSettingComparator .java .................................. 16
/connection
/connection.conWithCamera
/CamLiveStreamThread .java .................................. 17
/CamTakePicture .java ....................................... 19
/connection.conWithRobot
/CommunicationRobotThread .java ............................. 20
/console
/ConsoleCommands .java ............................................ 24
/ConsoleInputListener .java ....................................... 28
/ConsoleOutputStream .java ........................................ 30
/ViewConsolePanel .java ........................................... 32
/exceptions
/CubeletAlreadyAssignedException .java ............................ 39
/FaceletColorNoneException .java .................................. 40
/NoCaptureDevConnectionException .java ............................ 41
/NoImageForColorEstimationException .java ......................... 41
/NoMatchingSettingTypeException .java ............................. 42
/NonExistingCubeletException .java ................................ 43
/NoSuchSettingFoundException .java ................................ 44
/NotAvailableException .java ...................................... 44
/NotIntendedIPAddressException .java .............................. 45
/NoValidFileException .java ....................................... 45
/NumberNotFoundException .java .................................... 46
/WorkInProgressException .java .................................... 46

i CubeThesis™ Depamelaere-Deschuytter
/listeners
/aut
/B_AUT_AutomaticRoutineListener .java ....................... 47
/B_AUT_CommandToRobotListener .java ......................... 48
/B_AUT_StopAutoRoutineListener .java ........................ 48
/T_AUT_SubTasksItemListener .java ........................... 49
/cam
/B_CAM_ConnectCamListener .java ............................. 50
/B_CAM_ConnectRobotListener.java ............................ 50
/B_CAM_TakeAPictureListener .java ........................... 51
/T_CAM_LiveStreamItemListener .java ......................... 52
/cbthsettings
/MenuItemSortListener .java ................................. 55
/TF_SettingsCustomizerDocumentListener .java ................ 56
/TF_VisualCBTHSettingListener .java ......................... 57
/cube
/B_CUBE_AssignToMainCubeFaceListener .java .................. 58
/B_CUBE_BuildVirtualCubeListener .java ...................... 59
/B_CUBE_DeleteCubeFaceListener .java ........................ 60
/B_CUBE_NextCubeFaceListener .java .......................... 61
/B_CUBE_PreviousCubeFaceListener .java ...................... 62
/B_CUBE_TurnCFace90Degrees .java ............................ 63
/Co_CUBE_ColorsOnCubeFaceDropdownListener .java ............. 64
/Co_CUBE_MainCFacesDropdownListener .java ................... 66
/img
/B_IMG_BrowseImageListener .java ............................ 67
/B_IMG_ColorCalibrationListener .java ....................... 67
/B_IMG_ColorEstimationListener .java ........................ 68
/B_IMG_DeleteImageListener .java ............................ 69
/B_IMG_SaveImagesListener .java ............................. 69
/B_IMG_UpdateCropParamListener .java ........................ 70
/Co_IMG_CBTHImagesListDropdownListener .java ................ 71
/S_IMG_CropSpinnersListener .java ........................... 72
/menu
/MenuItemAboutListener .java ................................ 74
/MenuItemConsoleClearListener .java ......................... 75
/MenuItemCustomizeSettingsListener .java .................... 76
/MenuItemExitListener .java ................................. 77
/MenuItemExportSettingsToText .java ......................... 78
/MenuItemImportSettingsFromText .java ....................... 78
/MenuItemJavaDocListener .java .............................. 79
/MenuItemListCommandsListener .java ......................... 80
/MenuItemNewProjectListener .java ........................... 82
/MenuItemOpenProjectListener .java .......................... 83
/MenuItemRestoreFactorySettings .java ....................... 84
/MenuItemSaveAsProjectListener .java ........................ 84
/MenuItemSaveProjectListener .java .......................... 85
/MenuItemUserManualListener .java ........................... 86
/solv
/B_SOLV_BlenderGUIListener .java ............................ 88
/B_SOLV_CubeToSolverListener .java .......................... 89
/B_SOLV_EnumerateMovesListener .java ........................ 91
/B_SOLV_MoveSeqToRobotListener .java ........................ 92
/main
/Main .java ....................................................... 93

ii CubeThesis™ Depamelaere-Deschuytter
/model
/AutomaticRoutine .java ........................................... 96
/CBTHImage .java ................................................. 102
/CBTHImagesList .java ............................................ 106
/CBTHSetting .java ............................................... 109
/CBTHSettingsList .java .......................................... 112
/ColorEstimation .java ........................................... 129
/CommandSeq .java ................................................ 136
/CommonObjects .java ............................................. 145
/CubeConfiguration .java ......................................... 147
/CubeFace .java .................................................. 161
/CubeFacesList .java ............................................. 165
/solver.solverJS
/algorithm
/CubePosition .java ........................................ 169
/CubieSettings .java ....................................... 182
/MoveSequence .java ........................................ 183
/Solver .java .............................................. 190
/SolverAntiSlice .java ..................................... 194
/SolverKociemba .java ...................................... 203
/SolverSlice .java ......................................... 216
/SolverSquare .java ........................................ 224
/SolverTwoGen .java ........................................ 233
/viewSolverJS
/Cubie .java ............................................... 241
/SymButton .java ........................................... 255
/Viewer .java .............................................. 261
/Viewer3D .java ............................................ 265
/ViewerBox .java ........................................... 276
/ViewerDiag .java .......................................... 282
/ViewerFlat .java .......................................... 287
/view
/view.scrollImageView
/Corner .java .............................................. 290
/Ruler .java ............................................... 291
/ScrollablePicture .java ................................... 293
/ScrollImageJPanel .java ................................... 295
/TransparentSplashScreen .java ................................... 297
/ViewCubeThesis .java ............................................ 298
/ViewTabPanel0Cam .java .......................................... 304
/ViewTabPanel1Img .java .......................................... 306
/ViewTabPanel2Cub .java .......................................... 312
/ViewTabPanel3Sol .java .......................................... 316
/ViewTabPanel4Aut .java .......................................... 318
/ViewTabSubPanelAut .java ........................................ 322
/VisualCBTHSetting .java ......................................... 324
/VisualCBTHSettingsCustomizer .java .............................. 325
/VisualCubeFace .java ............................................ 327

iii CubeThesis™ Depamelaere-Deschuytter


class CBTHFileChooser

1 package cbthFileChooser;
2
3 import java.awt.*;
4 import java.io.*;
5 import javax.swing.*;
6
7 import model.CBTHSettingsList;
8 import model.CommonObjects;
9
10 public class CBTHFileChooser extends JFileChooser {
11
12 private static final long serialVersionUID = 1L;
13 public static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14 private JFrame parent;
15
16 // Constructors:
17 public CBTHFileChooser() {
18
19 // Set up the file chooser by invoking the 'super'() constructor:
20 super();
21
22 /*
23 * To give pop-up filechooser-window the Rubik's logo, a custom
24 * parent-JFrame object is created.
25 */
26 parent = cbthsl.createCubeThesisFrame(null);
27 this.createDialog(parent);
28
29 // Add custom icons for file types:
30 this.setFileView(new CBTHFileView());
31
32 // Add the preview pane:
33 this.setAccessory(new ImagePreview(this));
34
35 // Set the defaultLocation:
36 this.setCurrentDirectory(cbthsl.getCurrentProject());
37
38 }
39
40 // Instance methods:
41 /**
42 * Spawns the 'browsing' window on the screen.
43 *
44 * @param mode
45 * Specifies whether an image=0/savefile=1 is to be loaded.
46 * @return Mere a File (=filepath) is returned, so the actual interpreting of
47 * the data happens elsewhere.
48 */
49 public File fcOpenFile(int mode) {
50
51 /*
52 * Depending whether a savefile or an image is to be loaded (modus-param),
53 * the other filefilters are applied. The default location is specified.
54 */
55 switch (mode) {
56 default:
57 this.setAcceptAllFileFilterUsed(true);
58 break;
59 case 0:
60 System.out.println("FileChooser will load an image...");
61 this.addChoosableFileFilter(new ImageFilter());
62 this.setFileSelectionMode(JFileChooser.FILES_ONLY);
63 this.setAcceptAllFileFilterUsed(false);
64 break;
65 case 1:
66 System.out.println("FileChooser will load a CubeThesis-Savefile...");

Pagina 1 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHFileChooser

67 this.setCurrentDirectory(new File(cbthsl.getCurrentProject().getParent()));
68 this.addChoosableFileFilter(new EigExtFilter());
69 this.setFileSelectionMode(JFileChooser.FILES_ONLY);
70 this.setAcceptAllFileFilterUsed(true);
71 break;
72 }
73
74 // Pop-up the dialog:
75 int returnVal = this.showDialog((Component) parent, "Open");
76
77 // Process the results:
78 File file = null;
79 if (returnVal == JFileChooser.APPROVE_OPTION) {
80 file = this.getSelectedFile();
81 if (mode == 1) {
82 cbthsl.setCurrentProject(new File(file.getParent()));
83 }
84 }
85
86 else {
87 System.out.println("FileChooser cancelled.");
88 }
89 // Reset the file chooser for the next time it's shown:
90 this.setSelectedFile(null);
91
92 /*
93 * There's is only 1 CBTHFileChooser object in CubeThesis, that is recycled
94 * all the time. Opening/Saving of different file-formats require their
95 * proper FileFilters. So at the end of use, we remove all the applied
96 * FileFilters.
97 */
98 while (this.getFileFilter() != null) {
99 this.removeChoosableFileFilter(this.getFileFilter());
100 }
101
102 return file;
103 }
104
105 /**
106 * This method will be invoked when 'Saving As...', as is to say, when the
107 * name of the file or location needs to be changed.
108 *
109 * @param mode
110 * The modus alters certain settings of the filechooserobject.
111 * @return The File (=Filepath) where user wants CubeThesis to write the file.
112 */
113 public File fcSaveFile(int mode) {
114 // At this point, there's no switch construction required here.
115 // Only mode/case 0 is addressed.
116 switch (mode) {
117 default:
118 this.setAcceptAllFileFilterUsed(true);
119 break;
120 case 0:
121 System.out.println("FileChooser will save images...");
122 this.setCurrentDirectory(cbthsl.getCurrentProject());
123 this.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
124 this.addChoosableFileFilter(new ImageFilter());
125 this.setAcceptAllFileFilterUsed(true);
126 break;
127 case 1:
128 System.out.println("FileChooser will save current project...");
129 this.setCurrentDirectory(cbthsl.getCurrentProject());
130 this.setFileSelectionMode(JFileChooser.FILES_ONLY);
131 this.addChoosableFileFilter(new EigExtFilter());
132 this.setAcceptAllFileFilterUsed(true);

Pagina 2 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHFileChooser

133 break;
134 }
135
136 File fileToSave = null;
137 this.setSelectedFile
138 (new File("- Don't type here, navigate into the folder where "
139 + "the project needs to be saved. -"));
140 int returnVal = this.showDialog((Component) parent, "Save img/proj");
141
142 if (returnVal == JFileChooser.APPROVE_OPTION) {
143
144 fileToSave = this.getCurrentDirectory();
145 cbthsl.setCurrentProject(fileToSave);
146 switch (mode) {
147 default:
148 break;
149 case 0:
150 FileIO.savePhysicalImages();
151 break;
152 case 1:
153 FileIO.saveProject();
154 break;
155 }
156 }
157
158 else {
159 System.out.println("FileChooser cancelled.");
160 }
161
162 this.setSelectedFile(null);
163
164 /*
165 * There's is only 1 CBTHFileChooser object in CubeThesis, that is recycled
166 * all the time. Opening/Saving of different file-formats require their
167 * proper FileFilters. So at the end of use, we remove all the applied
168 * FileFilters.
169 */
170 while (this.getFileFilter() != null) {
171 this.removeChoosableFileFilter(this.getFileFilter());
172 }
173 return fileToSave;
174 }
175 }

Pagina 3 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHFileView

1 package cbthFileChooser;
2
3 import java.io.File;
4 import javax.swing.*;
5 import javax.swing.filechooser.*;
6
7 import model.CommonObjects;
8
9 public class CBTHFileView extends FileView {
10
11 private static ImageIcon jpgIcon = createImageIcon("JPG-icon.png");
12 private static ImageIcon gifIcon = createImageIcon("GIF-icon.png");
13 private static ImageIcon tiffIcon = createImageIcon("TIFF-icon.png");
14 private static ImageIcon pngIcon = createImageIcon("PNG-icon.png");
15 private static ImageIcon bmpIcon = createImageIcon("BMP-icon.png");
16 private static ImageIcon cbthExtensionIcon = createImageIcon("CBTH-icon.png");
17
18 // Constructors: Calling this constructor can be omitted. Nothing new happens.
19 public CBTHFileView() {
20 super();
21 }
22
23 // Getters:
24 public String getDescription(File f) {
25 return null; // let the L&F FileView figure this out
26 }
27
28 public Icon getIcon(File f) {
29 String extension = Utils.getExtension(f);
30 Icon icon = null;
31
32 if (extension != null) {
33 switch (extension) {
34 default:
35 break;
36 case Utils.jpeg:
37 case Utils.jpg:
38 icon = jpgIcon;
39 break;
40 case Utils.png:
41 icon = pngIcon;
42 break;
43 case Utils.gif:
44 icon = gifIcon;
45 break;
46 case Utils.tiff:
47 case Utils.tif:
48 icon = tiffIcon;
49 break;
50 case Utils.bmp:
51 icon = bmpIcon;
52 break;
53 case Utils.cbthExtension:
54 icon = cbthExtensionIcon;
55 break;
56 }
57
58 }
59 return icon;
60 }
61
62 public String getName(File f) {
63 return null; // let the L&F FileView figure this out
64 }
65
66 public String getTypeDescription(File f) {

Pagina 4 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHFileView

67 String extension = Utils.getExtension(f);


68 String type = null;
69
70 if (extension != null) {
71 switch (extension) {
72 default:
73 break;
74 case Utils.jpeg:
75 case Utils.jpg:
76 type = "JPEG-Image";
77 break;
78 case Utils.png:
79 type = "PNG-Image";
80 break;
81 case Utils.gif:
82 type = "GIF-Image";
83 break;
84 case Utils.tiff:
85 case Utils.tif:
86 type = "TIFF-Image";
87 break;
88 case Utils.bmp:
89 type = "BMP-Image";
90 break;
91 case Utils.cbthExtension:
92 type = Utils.cbthExtension + " File";
93 break;
94 }
95
96 }
97 return type;
98 }
99
100 // Instance methods:
101 public Boolean isTraversable(File f) {
102 return null; // let the L&F FileView figure this out
103 }
104
105 // Static methods:
106 public static ImageIcon createImageIcon(String iconFileName) {
107
108 String[] pathStruct = { "img", "icon", iconFileName };
109 String path =
110 CommonObjects.getCBTHSettingsList().makeSysIndepFilePath(pathStruct, 2);
111
112 ImageIcon iconToReturn = null;
113
114 try {
115 iconToReturn = new ImageIcon(path);
116 } catch (Exception exp) {
117 System.err.println
118 ("ERROR: CBTHFileChooser: No ImageIcon made. Path/File is not valid.");
119 }
120 return iconToReturn;
121 }
122 }

Pagina 5 van 329 CubeThesis™ Depamelaere-Deschuytter


class EigExtFilter

1 package cbthFileChooser;
2
3 import java.io.File;
4 import javax.swing.filechooser.*;
5
6 public class EigExtFilter extends FileFilter {
7
8 // Instance methods:
9 /** Accepts directories and the cbthExtension. */
10 public boolean accept(File f) {
11 if (f.isDirectory()) {
12 return true;
13 }
14
15 String extension = Utils.getExtension(f);
16 if (extension != null) {
17 if (extension.equals(Utils.cbthExtension)) {
18 return true;
19 } else {
20 return false;
21 }
22 }
23 return false;
24 }
25
26 // Getters:
27 // The description of this filter:
28 public String getDescription() {
29 return "CubeThesis savefiles only (." + Utils.cbthExtension + ")";
30 }
31 }

Pagina 6 van 329 CubeThesis™ Depamelaere-Deschuytter


class FileIO

1 package cbthFileChooser;
2
3 import java.io.*;
4 import java.text.DateFormat;
5 import java.text.SimpleDateFormat;
6 import java.util.Date;
7
8 import exceptions.NoValidFileException;
9 import model.*;
10
11 public class FileIO {
12
13 private static CBTHImagesList imgl;
14 private static CubeFacesList cfl;
15 private static CBTHSettingsList cbthsl;
16
17 // Constructors:
18 public FileIO(CBTHImagesList imgl, CubeFacesList cfl) {
19
20 // Als deze mappen nog niet zouden bestaan kunnen ze nog worden aangemaakt,
21 // bestonden ze wel imgl, dan worden ze niet overschreven
22 FileIO.imgl = imgl;
23 FileIO.cfl = cfl;
24 FileIO.cbthsl = CommonObjects.getCBTHSettingsList();
25 }
26
27 // Static methods:
28 /**
29 * Opens a project from a certain savefile.
30 *
31 * @param cbthFile
32 * The savefile was acquired by the cbthfilechooser.
33 */
34 public static void openProject(File cbthFile) {
35
36 try {
37 if (cbthFile == null) {
38 throw new NoValidFileException(".cbth");
39 }
40
41 FileInputStream fis = null;
42 DataInputStream dis = null;
43 System.out.println("Project will be loaded from file: " + cbthFile);
44
45 // Before reading the saveFile, current data is reset:
46 imgl.deleteAllCBTHImages();
47 cfl.deleteAllCubeFaces();
48 cfl.resetMainCubeFaces();
49 CubeConfiguration.setStartCubeletPerm(null);
50 CubeConfiguration.setStartCubeletOri(null);
51 CubeConfiguration.setStartFaceOri(null);
52 CubeConfiguration.setColorMapKey(null);
53 CommandSeq.stopAsQuicklyAsPossile();
54 CommandSeq.setSolutionCommandsMatrix(null, null, 0);
55
56 try {
57 boolean stop = false;
58 try {
59 fis = new FileInputStream(cbthFile);
60 dis = new DataInputStream(fis);
61 } catch (FileNotFoundException fnfe) {
62 stop = true;
63 System.err.println("ERROR: Specified file couldn't be found.");
64 }
65
66 boolean[] dataBlockSystem;

Pagina 7 van 329 CubeThesis™ Depamelaere-Deschuytter


class FileIO

67
68 while (!stop) {
69 try {
70 int amountDataBlocks = dis.readInt();
71 dataBlockSystem = new boolean[amountDataBlocks];
72
73 for (int q = 0; q < amountDataBlocks; q++) {
74 dataBlockSystem[q] = dis.readBoolean();
75 }
76
77 // BLOCK 0: Read image-references +
78 // loading the images to the CBTHImagesList.
79 if (dataBlockSystem[0]) {
80 imgl.cbthImagesListFromSaveFile(dis);
81 System.out.println("Image-references were loaded properly.");
82 }
83
84 // BLOCK 1: Loading mainCubeFaces & CubeFaces to their
85 // respective lists.
86 if (dataBlockSystem[1]) {
87 // Loading MainCubeFaces:
88 cfl.mainCubeFacesFromSaveFile(dis);
89 System.out.println("Main-cubefaces were loaded properly.");
90
91 // Loading CubeFaces:
92 cfl.cubeFacesFromSaveFile(dis);
93 System.out.println("Cubefaceslist was loaded properly.");
94 }
95
96 // BLOCK 2: Potential Cube-configuration is loaded.
97 if (dataBlockSystem[2]) {
98 CubeConfiguration.cubeConfigFromSaveFile(dis);
99 System.out.println(
100 "Cube-configuration & colormapkey were loaded " + "properly.");
101 }
102
103 // BLOCK 3: Potential cube-solution is being loaded &
104 // info on the progress of the robot.
105 if (dataBlockSystem[3]) {
106 CommandSeq.commandSeqFromSaveFile(dis);
107 System.out.println(
108 "Cube-solution and the robot's progress " + "are loaded properly.");
109 }
110
111 System.out.println(
112 "Project \"" + cbthFile.getName() + "\" was loaded properly.");
113
114 } catch (EOFException eofe) {
115 stop = true;
116 }
117 }
118 } catch (IOException ioe) {
119 System.err.println("ERROR: An IOException occurred during opening "
120 + "the SaveFile.cbth. Our apologies for the inconvenience.");
121 }
122
123 finally {
124 if (dis != null) {
125 try {
126 dis.close();
127 } catch (IOException ioe) {
128 System.err.println(
129 "ERROR: An IOException occurred during closing \"dis\"."
130 + " Our apologies for the inconvenience.");
131 }
132 } else {

Pagina 8 van 329 CubeThesis™ Depamelaere-Deschuytter


class FileIO

133 if (fis != null) {


134 try {
135 fis.close();
136 } catch (IOException ioe) {
137 System.err.println(
138 "ERROR: An IOException occurred during closing \"dis\"."
139 + " Our apologies for the inconvenience.");
140 }
141 }
142 }
143 }
144 } catch (NoValidFileException exp) {
145 System.err.println(exp);
146 }
147 }
148
149 /**
150 * Only saves the physical images (=.png, .jpg, .tiff, .bmp, .gif - files).
151 */
152 public static void savePhysicalImages() {
153
154 try {
155 imgl.cbthImagesListToImageFiles();
156 System.out.println("Physical images were saved properly.");
157 } catch (IOException exp) {
158 System.err.println(
159 "ERROR: An IOException occurred during saving of the images. "
160 + "Our apologies for the inconvenience.");
161 }
162 }
163
164 /**
165 * Will save a project to the "currentProject"-location. (Images included.)
166 */
167 public static void saveProject() {
168
169 File currentProject = cbthsl.getCurrentProject();
170
171 System.out.println("Current project will be saved to: " + currentProject);
172
173 /*
174 * Savefile = binary file with the following content: - Which images make
175 * part of the project (relative filepaths). - CubeFaces and assigned
176 * maincubefaces. - Cube-configuration if available yet. - The solution
177 * produced by Cubie & CubeThesis' translation + info upon the robot's
178 * progress.
179 *
180 * The savefile itself is organized as several datablocks, written one after
181 * the other. Each of them contains a certain type of data.
182 */
183
184 FileOutputStream fos = null;
185 DataOutputStream dos = null;
186
187 try {
188 String[] pathStruct = { "SaveFileCBTH." + Utils.cbthExtension };
189 fos = new FileOutputStream(cbthsl.makeSysIndepFilePath(pathStruct, 3));
190 dos = new DataOutputStream(fos);
191
192 // Check what data is available to save:
193 int sizeImglArray = imgl.getSize();
194 boolean writeCBTHImageRefs = sizeImglArray != 0;
195
196 int sizeCflArray = cfl.getSize();
197 boolean writeCubeFaces = sizeCflArray != 0;
198

Pagina 9 van 329 CubeThesis™ Depamelaere-Deschuytter


class FileIO

199 boolean writeCubeConfiguration = false;


200 if (CubeConfiguration.getStartCubeletPerm() != null
201 && CubeConfiguration.getStartCubeletOri() != null
202 && CubeConfiguration.getStartFaceOri() != null) {
203 writeCubeConfiguration = true;
204 }
205
206 boolean writeCommandSeq = CommandSeq.commandSeqWorthSaving();
207
208 int amountDataBlocks = 4;
209 boolean[] dataBlockSystem = new boolean[amountDataBlocks];
210 // Referenties naar afbeeldingen (filepaden) moeten enkel worden
211 // weggeschreven als de AfbeeldingsLisjt afbeeldingen bevatte.
212 dataBlockSystem[0] = writeCBTHImageRefs;
213 dataBlockSystem[1] = writeCubeFaces;
214 dataBlockSystem[2] = writeCubeConfiguration;
215 dataBlockSystem[3] = writeCommandSeq;
216
217 dos.writeInt(amountDataBlocks);
218 for (int t = 0; t < amountDataBlocks; t++) {
219 dos.writeBoolean(dataBlockSystem[t]);
220 }
221
222 // BLOCK 0: Save physical images & Write image-references
223 // from the imgl.
224 if (dataBlockSystem[0]) {
225 // Both "physical" images as the references to them are saved.
226 savePhysicalImages();
227 dos.writeInt(imgl.getSize());
228 imgl.cbthImagesListToSaveFile(dos);
229 System.out.println("Image-references were saved properly.");
230 }
231
232 // BLOCK 1: Saving mainCubeFaces & CubeFaces.
233 if (dataBlockSystem[1]) {
234
235 cfl.mainCubeFacesToSaveFile(dos);
236 System.out.println("Maincubefaces were saved properly.");
237
238 dos.writeInt(sizeCflArray);
239 cfl.cubeFacesToSaveFile(dos);
240 System.out.println("Cubefaces were saved properly.");
241
242 }
243
244 // BLOCK 2: Potential Cube-configuration is saved.
245 if (dataBlockSystem[2]) {
246 CubeConfiguration.cubeConfigToSaveFile(dos);
247 System.out.println("Cube-configuration was saved properly.");
248 }
249
250 // BLOCK 3: Potential cube-solution & info on the progress of
251 // the robot.
252 if (dataBlockSystem[3]) {
253 CommandSeq.commandSeqToSaveFile(dos);
254 System.out.println("Info about the cube-solution was saved properly.");
255 }
256
257 // BLOCK 4:...
258
259 // ...
260
261 // Finally confirm that the saving-procedure was performed correctly:
262 DateFormat dateFormat2 = new SimpleDateFormat("HH:mm:ss");
263 Date date = new Date();
264 String datumToString = dateFormat2.format(date);

Pagina 10 van 329 CubeThesis™ Depamelaere-Deschuytter


class FileIO

265 System.out.println("Project \"" + cbthsl.getCurrentProject().getName()


266 + "\" was saved at: " + datumToString);
267
268 } catch (IOException ioe) {
269 System.err.println("ERROR: An IOException occurred during writing file. "
270 + "Our apologies for the inconvenience.");
271 }
272
273 finally {
274 if (dos != null) {
275 try {
276 dos.close();
277 } catch (IOException ioe) {
278 System.err.println(
279 "ERROR: An IOException occurred during closing of \"dos\". "
280 + "Our apologies for the inconvenience.");
281 }
282 } else {
283 if (fos != null) {
284 try {
285 fos.close();
286 } catch (IOException ioe) {
287 System.err.println(
288 "ERROR: An IOException occurred during closing of \"fos\". "
289 + "Our apologies for the inconvenience.");
290 }
291 }
292 }
293 }
294 }
295 }

Pagina 11 van 329 CubeThesis™ Depamelaere-Deschuytter


class ImageFilter

1 package cbthFileChooser;
2
3 import java.io.File;
4 import javax.swing.filechooser.*;
5
6 public class ImageFilter extends FileFilter {
7
8 // Instance methods:
9 /** Accepts directories and image formats (gif, jpg, tiff, bmp or png). */
10 public boolean accept(File f) {
11 if (f.isDirectory()) {
12 return true;
13 }
14
15 String extension = Utils.getExtension(f);
16 if (extension != null) {
17 if (extension.equals(Utils.tiff) || extension.equals(Utils.tif)
18 || extension.equals(Utils.gif) || extension.equals(Utils.jpeg)
19 || extension.equals(Utils.jpg) || extension.equals(Utils.bmp)
20 || extension.equals(Utils.png)) {
21 return true;
22 } else {
23 return false;
24 }
25 }
26
27 return false;
28 }
29
30 // Getters:
31 // The description of this filter
32 public String getDescription() {
33 return "Imageformats only (." + Utils.jpg + "; ."
34 + Utils.jpeg + "; ." + Utils.png
35 + ";" + " ." + Utils.gif + "; ." + Utils.bmp + "; ." + Utils.tif + "; ."
36 + Utils.tiff + ").";
37 }
38 }

Pagina 12 van 329 CubeThesis™ Depamelaere-Deschuytter


class ImagePreview

1 package cbthFileChooser;
2
3 import java.awt.*;
4 import java.beans.*;
5 import java.io.File;
6 import javax.swing.*;
7
8 public class ImagePreview extends JComponent implements PropertyChangeListener {
9
10 private static final long serialVersionUID = -7707572607662984788L;
11 private ImageIcon thumbnail = null;
12 private File file = null;
13
14 // Constructors:
15 public ImagePreview(JFileChooser fc) {
16 setPreferredSize(new Dimension(100, 50));
17 fc.addPropertyChangeListener(this);
18 }
19
20 // Instance methods:
21 public void loadImage() {
22 if (file == null) {
23 thumbnail = null;
24 return;
25 }
26
27 // Don't use createImageIcon (which is a wrapper for getResource)
28 // because the image we're trying to load is probably not one
29 // of this program's own resources.
30 ImageIcon tmpIcon = new ImageIcon(file.getPath());
31 if (tmpIcon != null) {
32 if (tmpIcon.getIconWidth() > 90) {
33 thumbnail = new ImageIcon(
34 tmpIcon.getImage().getScaledInstance(90, -1, Image.SCALE_DEFAULT));
35 } else { // no need to miniaturize
36 thumbnail = tmpIcon;
37 }
38 }
39 }
40
41 protected void paintComponent(Graphics g) {
42 if (thumbnail == null) {
43 loadImage();
44 }
45 if (thumbnail != null) {
46 int x = getWidth() / 2 - thumbnail.getIconWidth() / 2;
47 int y = getHeight() / 2 - thumbnail.getIconHeight() / 2;
48
49 if (y < 0) {
50 y = 0;
51 }
52
53 if (x < 5) {
54 x = 5;
55 }
56 thumbnail.paintIcon(this, g, x, y);
57 }
58 }
59
60 public void propertyChange(PropertyChangeEvent e) {
61 boolean update = false;
62 String prop = e.getPropertyName();
63
64 // If the directory changed, don't show an image.
65 if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) {
66 file = null;

Pagina 13 van 329 CubeThesis™ Depamelaere-Deschuytter


class ImagePreview

67 update = true;
68
69 // If a file became selected, find out which one.
70 } else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) {
71 file = (File) e.getNewValue();
72 update = true;
73 }
74
75 // Update the preview accordingly.
76 if (update) {
77 thumbnail = null;
78 if (isShowing()) {
79 loadImage();
80 repaint();
81 }
82 }
83 }
84 }

Pagina 14 van 329 CubeThesis™ Depamelaere-Deschuytter


class Utils

1 package cbthFileChooser;
2
3 import java.io.File;
4
5 public class Utils {
6 public final static String jpeg = "jpeg";
7 public final static String jpg = "jpg";
8 public final static String gif = "gif";
9 public final static String tiff = "tiff";
10 public final static String tif = "tif";
11 public final static String png = "png";
12 public final static String bmp = "bmp";
13 public final static String cbthExtension = "cbth";
14
15 // Static methods:
16 /** Gets the extension of a file. */
17 public static String getExtension(File f) {
18 String ext = null;
19 String s = f.getName();
20 int i = s.lastIndexOf('.');
21
22 if (i > 0 && i < s.length() - 1) {
23 ext = s.substring(i + 1).toLowerCase();
24 }
25 return ext;
26 }
27 }

Pagina 15 van 329 CubeThesis™ Depamelaere-Deschuytter


class IdCBTHSettingComparator , LabelTextCBTHSettingComparator , TypeCBTHSettingComparator

1 package comparators;
2
3 import java.util.Comparator;
4
5 import model.CBTHSetting;
6
7 /** Compares CBTHSettings on their iD. */
8 public class IdCBTHSettingComparator implements Comparator<CBTHSetting> {
9
10 public int compare(CBTHSetting s1, CBTHSetting s2) {
11 return s1.getiD() - s2.getiD();
12 }
13 }

1 package comparators;
2
3 import java.util.Comparator;
4
5 import model.CBTHSetting;
6
7 /** Compares CBTHSettings alphabetically on their labeltext. */
8 public class LabelTextCBTHSettingComparator implements Comparator<CBTHSetting> {
9
10 public int compare(CBTHSetting s1, CBTHSetting s2) {
11 return (s1.getLabelText()).compareToIgnoreCase(s2.getLabelText());
12 }
13 }

1 package comparators;
2
3 import java.util.Comparator;
4
5 import model.CBTHSetting;
6
7 /** Compares CBTHSettings alphabetically on their type. */
8 public class TypeCBTHSettingComparator implements Comparator<CBTHSetting> {
9
10 public int compare(CBTHSetting s1, CBTHSetting s2) {
11 return (s1.getType().compareTo(s2.getType()));
12 }
13 }

Pagina 16 van 329 CubeThesis™ Depamelaere-Deschuytter


class CamLiveStreamThread

1 package connection.conWithCamera;
2
3 import java.awt.image.BufferedImage;
4 import java.awt.image.DataBufferByte;
5 import javax.swing.ImageIcon;
6 import javax.swing.JLabel;
7
8 import model.CBTHSettingsList;
9 import model.CommonObjects;
10 import org.opencv.core.Mat;
11 import org.opencv.videoio.VideoCapture;
12
13 public class CamLiveStreamThread implements Runnable {
14 /*
15 * Source: http://stackoverflow.com/questions/26535645/
16 * ip-camera-with-opencv-in-java visited the 30/09/2015. Source:
17 * https://www.youtube.com/watch?v=paYDSGtneDQ visited the 7/10/2015. Source:
18 * http://docs.opencv.org/3.0-beta/doc/tutorials/introduction/
19 * java_eclipse/java_eclipse.html visited the 7/10/2015
20 */
21
22 public static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
23 public volatile boolean runnable = false;
24 /*
25 * When two threads synchronously invert the same boolean, AtomicBoolean would
26 * have been a better choice, then the result is guaranteed to be the original
27 * boolean-value. More info? Source:
28 * http://stackoverflow.com/questions/15735366/
29 * accessing-boolean-in-a-multithreaded-environment
30 */
31
32 private volatile VideoCapture captureDevice;
33 private volatile JLabel l_CAM_StreamToLabel;
34 private volatile BufferedImage image;
35 private Mat frame;
36
37 // Constructor:
38 public CamLiveStreamThread(VideoCapture captureDevice, JLabel l_CAM_StreamToLabel) {
39 this.captureDevice = captureDevice;
40 this.l_CAM_StreamToLabel = l_CAM_StreamToLabel;
41 this.frame = new Mat();
42 this.image = null;
43 }
44
45 // Getter:
46 public BufferedImage getCurrentFrame() {
47 return image;
48 }
49
50 // Instance method:
51 public BufferedImage Mat2BufferedImage(Mat m) {
52
53 int type = BufferedImage.TYPE_BYTE_GRAY;
54 if (m.channels() > 1) {
55 type = BufferedImage.TYPE_3BYTE_BGR;
56 }
57 int bufferSize = m.channels() * m.cols() * m.rows();
58 byte[] b = new byte[bufferSize];
59 m.get(0, 0, b); // get all the pixels
60
61 BufferedImage img = new BufferedImage(m.cols(), m.rows(), type);
62 final byte[] targetPixels = ((DataBufferByte) img.getRaster().getDataBuffer())
63 .getData();
64 System.arraycopy(b, 0, targetPixels, 0, b.length);
65 return img;
66 }

Pagina 17 van 329 CubeThesis™ Depamelaere-Deschuytter


class CamLiveStreamThread

67
68 /** This method describes the refreshing process of the cameraframes. */
69 public void run() {
70 synchronized (this) {
71
72 while (runnable) {
73 if (captureDevice.grab()) {
74 try {
75 /*
76 * captureDevice.grab(); is faster but does not respect
77 * camera-synchronisation, although it also works fine in this
78 * application.
79 */
80 if (captureDevice.retrieve(frame)) {
81 image = Mat2BufferedImage(frame);
82 if (image != null) {
83 l_CAM_StreamToLabel.setIcon(new ImageIcon(image));
84 }
85 }
86
87 if (runnable == false) {
88 // Show screen with camerapicture and message how
89 // to retrieve a livestream.
90 String[] pathComp = { "img", "icon", "CAMdfk23g445.png" };
91 String iconPath = cbthsl.makeSysIndepFilePath(pathComp, 2);
92 l_CAM_StreamToLabel.setIcon(new ImageIcon(iconPath));
93 l_CAM_StreamToLabel.setText(
94 " Toggle \"Camera livestream\" to "
95 + "retrieve a videostream from CaptureDevice.");
96 l_CAM_StreamToLabel.setFont(cbthsl.getFont("guiFont1"));
97
98 System.out.println("[CAMLINK]: Camera LivestreamTread stopped.");
99 this.wait();
100 }
101 } catch (Exception ex) {
102 System.out.println(ex);
103 }
104 } else {
105 System.err.println(
106 "[CAMLINK]: ERROR: There are no frames to be grabbed.");
107 }
108 }
109 }
110 }
111 }

Pagina 18 van 329 CubeThesis™ Depamelaere-Deschuytter


class CamTakePicture

1 package connection.conWithCamera;
2
3 import java.awt.image.BufferedImage;
4 import java.text.DateFormat;
5 import java.text.SimpleDateFormat;
6 import java.util.Date;
7
8 import exceptions.NoCaptureDevConnectionException;
9 import listeners.cam.T_CAM_LiveStreamItemListener;
10 import model.CBTHImage;
11 import model.CBTHSettingsList;
12 import model.CommonObjects;
13
14 public class CamTakePicture {
15
16 private static int shotID;
17 private static T_CAM_LiveStreamItemListener lsil;
18 private static DateFormat dateFormat;
19 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
20
21 // Constructor:
22 public CamTakePicture(T_CAM_LiveStreamItemListener lsiListener) {
23 shotID = 0;
24 lsil = lsiListener;
25 dateFormat = new SimpleDateFormat("_yyyy_MM_dd_HH_mm_ss");
26 // 2014/08/06 15:59:48
27 }
28
29 public static CBTHImage takePicture() throws NoCaptureDevConnectionException {
30 BufferedImage frame = lsil.getCurrentFrame();
31 CBTHImage a = null;
32
33 if (frame != null) {
34
35 Date date = new Date();
36
37 String bestandsNaam = "SnapshotId" + shotID + dateFormat.format(date);
38 shotID++;
39
40 a = new CBTHImage(bestandsNaam, frame);
41
42 int tempXCrop = cbthsl.getInt("xCoCrop");
43 int tempYCrop = cbthsl.getInt("yCoCrop");
44 int tempWidthCrop = cbthsl.getInt("widthCrop");
45 int tempHeightCrop = cbthsl.getInt("heightCrop");
46
47 // Avoid Raster error, i.e.: cropping an image with invalid coordinates.
48 if (tempXCrop + tempWidthCrop < lsil.getCapDeviceFrameWidth()
49 && tempYCrop + tempHeightCrop < lsil.getCapDeviceFrameHeight()) {
50 a.setNewCropped(tempXCrop, tempYCrop, tempWidthCrop, tempHeightCrop);
51 }
52 } else {
53 System.err.println(
54 "[CAMLINK]: ERROR: There was no frame " + "passed to process.");
55 }
56 return a;
57 }
58 }

Pagina 19 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommunicationRobotThread

1 package connection.conWithRobot;
2
3 import java.io.*;
4 import java.net.*;
5
6 import exceptions.NotIntendedIPAddressException;
7 import model.CBTHSettingsList;
8 import model.CommandSeq;
9 import model.CommonObjects;
10
11 public class CommunicationRobotThread extends Thread {
12 // Source:
13 // https://www.cs.uic.edu/~troy/spring05/cs450/sockets/EchoServer2.java
14
15 public static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
16 protected Socket clientSocket;
17 private ServerSocket serverSocket;
18 private int portNumber;
19 private PrintWriter out;
20 private DataInputStream dis;
21 private volatile boolean loopMaintained;
22 private volatile boolean linkRobotEstablished;
23 private volatile boolean robotIsBusy;
24
25 // Constructor:
26 public CommunicationRobotThread() {
27
28 this.serverSocket = null;
29 this.clientSocket = null;
30 this.portNumber = cbthsl.getInt("portNmbrServerSocket");
31
32 this.out = null;
33 this.dis = null;
34
35 this.linkRobotEstablished = false;
36 this.robotIsBusy = false;
37 }
38
39 // Getters:
40 public boolean getLinkRobotEstablished() {
41 return linkRobotEstablished;
42 }
43
44 public boolean getRobotIsBusy() {
45 return robotIsBusy;
46 }
47
48 // Setters:
49 public void initializeCommunicationRobot() {
50
51 loopMaintained = true;
52 }
53
54 public void stopCommunicationRobot() {
55 CommandSeq.stopAsQuicklyAsPossile();
56 CommandSeq.terminateRobotProgram();
57
58 // Wait till the robot has moved aside:
59 try {
60 Thread.sleep(3000); // 1000 milliseconds is one second.
61 } catch (InterruptedException ex) {
62 Thread.currentThread().interrupt();
63 }
64 loopMaintained = false;
65 }
66

Pagina 20 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommunicationRobotThread

67 /** In the run method, the communicationroutine is executed. */


68 public void run() {
69
70 while (loopMaintained) {
71 // Try to connect with new client as long as boolean==true.
72 try {
73 portNumber = cbthsl.getInt("portNmbrServerSocket");
74 serverSocket = new ServerSocket(portNumber);
75 clientSocket = null;
76 // System.out.println("[ROBOTLINK]: Connection Socket Created");
77
78 System.out.println(
79 "[ROBOTLINK]: CommunicationThread requires incoming call from "
80 + "the robotcontroller.");
81 System.out.println(
82 "[ROBOTLINK]: The user can continue working " + "in the meantime.");
83
84 /*
85 * Omitting next while loop should normally have any effect. In
86 * serverSockt.accept(). Java waits till a client makes connection. The
87 * while below was written to explicitly show the program waits for a
88 * client.
89 */
90 while (!serverSocket.isBound() || clientSocket == null) {
91 clientSocket = serverSocket.accept();
92 }
93
94 try {
95 out = new PrintWriter(clientSocket.getOutputStream(), true);
96 dis = new DataInputStream(clientSocket.getInputStream());
97 // Use DataInputStream rather than in
98 // = /*new BufferedReader(*/new InputStreamReader
99 // (clientSocket.getInputStream())/*)*/;
100
101 // Info upon the connection made is printed out:
102 System.out.println("------------");
103 System.out.println("[ROBOTLINK]: Client-Socket: " + clientSocket);
104 String ipAddressClient= clientSocket.getRemoteSocketAddress().toString();
105 System.out.println("[ROBOTLINK]: Client's IP-Address: "+ipAddressClient);
106
107 if (!ipAddressClient.equals(
108 "/" + cbthsl.getString("ipAddressRobot") + ":"
109 + clientSocket.getPort())) {
110 throw new NotIntendedIPAddressException("Robot", ipAddressClient,
111 "/" + cbthsl.getString("ipAddressRobot") + ":"
112 + clientSocket.getPort());
113 }
114 linkRobotEstablished = true;
115 // At this point Java is sure it made a connection with
116 // the intended device.
117 System.out.println("------------");
118
119 int inputChar;
120 int currentCommand = 0, noValidCommand = cbthsl.getInt("noValidCommand");
121
122 while (loopMaintained) {
123
124 /*
125 * 1: Getting the next command to send (peek = only looking at the
126 * next command, without removing it from the queue.) 2: The robot's
127 * answer is awaited, visualization will update if the command
128 * differs from 3 or 5 and the respective CBTHSetting was set true.
129 * 3: When the received command from the robotcontroller equals the
130 * command sent, the command will be removed from the queue. (The
131 * command is polled.) If both don't match, the same command will be
132 * sent again during next iteration of the loop.

Pagina 21 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommunicationRobotThread

133 */
134
135 currentCommand = CommandSeq.peekCommand();
136
137 if (currentCommand != noValidCommand) {
138
139 out.println(currentCommand);
140 System.out.println("[ROBOTLINK]: " + currentCommand
141 + " was successfully sent to the contoller.");
142 robotIsBusy = true;
143
144 // Instead of a fixed delaytime, the program waits
145 // for the robot's answer.
146 StringBuffer sb = new StringBuffer();
147
148 do {
149 inputChar = dis.read();
150 sb.append(Character.toString((char) inputChar));
151 } while (inputChar != 93);
152
153 System.out.println("[ROBOTLINK]: Robot replies: " + sb.toString());
154 robotIsBusy = false;
155
156 try {
157 int uitgevoerdCommando = textBetweenBrackets(sb.toString());
158
159 if (currentCommand == uitgevoerdCommando) {
160 CommandSeq.pollCommand();
161 }
162
163 } catch (NumberFormatException nfe) {
164 }
165 }
166
167 else {
168
169 /*
170 * When the commands run short in the queue, the queue is checked
171 * for new commands at 2Hz rate.
172 */
173 try {
174 Thread.sleep(500); // 1000 milliseconds is
175 // one second.
176 } catch (InterruptedException ex) {
177 Thread.currentThread().interrupt();
178 }
179 }
180
181 }
182
183 linkRobotEstablished = false;
184 out.close();
185 dis.close();
186 clientSocket.close();
187
188 } catch (IOException e) {
189 System.err.println(
190 "[ROBOTLINK]: ERROR: Problem with Communication Server");
191 } catch (NotIntendedIPAddressException niipae) {
192 System.err.println(niipae);
193 }
194
195 } catch (IOException exc1) {
196 System.err.println(
197 "[ROBOTLINK]: ERROR: Socketcreation: Could not listen on port "
198 + portNumber + " or socket was not accepted.");

Pagina 22 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommunicationRobotThread

199 try {
200 serverSocket.close();
201 System.out.println(
202 "[ROBOTLINK]: Socket was closed. Communication finished.");
203 } catch (IOException exc2) {
204 System.err.println(
205 "[ROBOTLINK]: ERROR: Port " + portNumber + " could not be shut down.");
206 }
207 }
208
209 finally {
210 // What happens after the try{}-block no matter whether an
211 // Exception occurred.
212 }
213 }
214 }
215
216 // Static method:
217 public static int textBetweenBrackets(String robotResponse)
218 throws NumberFormatException {
219
220 int temporary = cbthsl.getInt("noValidCommand");
221 temporary = Integer.parseInt(
222 robotResponse.substring(1, robotResponse.length() - 1));
223
224 return temporary;
225 }
226 }

Pagina 23 van 329 CubeThesis™ Depamelaere-Deschuytter


class ConsoleCommands

1 package console;
2
3 import java.io.File;
4
5 import javax.swing.Icon;
6 import javax.swing.JFrame;
7 import javax.swing.JOptionPane;
8 import javax.swing.JPanel;
9
10 import cbthFileChooser.CBTHFileChooser;
11 import cbthFileChooser.FileIO;
12 import connection.conWithCamera.CamTakePicture;
13 import exceptions.*;
14 import listeners.solv.*;
15 import model.*;
16 import solver.solverJS.viewSolverJS.Cubie;
17
18 /**
19 * This class organizes some basic commands that can be executed from the
20 * commandprompt. If you might want to add extra functions, just add a new line
21 * in the "SUPPORTED_COMMANDS" and implement the extra line in the switch-case
22 * structure in "executeCommand". No indexes are to be changed and order
23 * shouldn't necessarily be kept alphabetical.
24 */
25 public class ConsoleCommands {
26
27 /* In Alphabetical order supported commands are listed. */
28 private static final String[][] SUPPORTED_COMMANDS = {
29 { "BUILDVIRTCUBE", "Builds virtual cube if mainCubeFaces are available." },
30 { "CLEARALL", "Clears all the images, cubefaces... (Resets current data.)" },
31 { "CUBETOSOLVER", "Transfers the virtual cube to the solver." },
32 { "OPEN", "Spawns dialog to open a project." },
33 { "SAVE", "Saves the project at the current location." },
34 { "SAVEAS", "Spawns the \"Save as\"-dialog." },
35 { "SNAPESTIM",
36 "If a cameraconnection was put up, this will take a "
37 + "snapshot & perform colorestimation." },
38 { "SOLTOROBOT", "Translates the solution for the Robot." },
39 { "SOLVE", "Cubie will try to solve the cube shown in visualization." }, };
40 private static CBTHImagesList imgl = null;
41 private static CubeFacesList cfl = null;
42 private static CBTHFileChooser cbthfc = null;
43 private static ViewConsolePanel p_vcp = null;
44 private static CBTHSettingsList cbthsl = null;
45 private static B_SOLV_CubeToSolverListener cts = null;
46 private static B_SOLV_MoveSeqToRobotListener mstr = null;
47 private static Cubie cubie = null;
48
49 public ConsoleCommands(CBTHImagesList imgList, CubeFacesList cfList,
50 CBTHFileChooser cbthFileChooser, ViewConsolePanel p_VCP) {
51 imgl = imgList;
52 cfl = cfList;
53 cbthfc = cbthFileChooser;
54 p_vcp = p_VCP;
55 cbthsl = CommonObjects.getCBTHSettingsList();
56 cts = CommonObjects.getCubeToSolver();
57 mstr = CommonObjects.getMoveSeqToRobot();
58 cubie = CommonObjects.getCubie();
59 }
60
61 // Getter:
62 public static String[][] getSupCommands() {
63 return SUPPORTED_COMMANDS;
64 }
65
66 // Static methods:

Pagina 24 van 329 CubeThesis™ Depamelaere-Deschuytter


class ConsoleCommands

67 /**
68 * Checks whether the entered input is a real command.
69 *
70 * @param inputCommandPrompt
71 * User's input from the commandPrompt is passed here.
72 * @return The index at which the command is to be found.
73 */
74 public static int validCommand(String inputCommandPrompt) {
75 int returnValue = -1, index = 0;
76 boolean foundYet = false;
77
78 while (index < SUPPORTED_COMMANDS.length && !foundYet) {
79 // Commands are not case-sensitive:
80 if (inputCommandPrompt.equalsIgnoreCase(SUPPORTED_COMMANDS[index][0])) {
81 returnValue = index;
82 foundYet = true;
83 }
84 index++;
85 }
86 return returnValue;
87 }
88
89 /**
90 * Execute a specified command.
91 *
92 * @param commandIndex
93 * The index at which the command is to be found.
94 */
95 public static void executeCommand(int commandIndex) {
96
97 switch (SUPPORTED_COMMANDS[commandIndex][0]) {
98 case "BUILDVIRTCUBE":
99 try {
100 CubeConfiguration.buildVirtualCube(cfl.getAllMainCubeFaces());
101 } catch (FaceletColorNoneException fcne) {
102 System.err.println(fcne);
103 } catch (NonExistingCubeletException nece) {
104 System.err.println(nece);
105 } catch (CubeletAlreadyAssignedException caae) {
106 System.err.println(caae);
107 }
108 break;
109
110 case "CLEARALL":
111
112 int answer = showWarningMessage();
113
114 switch (answer) {
115 case JOptionPane.YES_OPTION:
116 imgl.deleteAllCBTHImages();
117 cfl.deleteAllCubeFaces();
118 cfl.resetMainCubeFaces();
119 CubeConfiguration.setStartCubeletPerm(null);
120 CubeConfiguration.setStartCubeletOri(null);
121 CubeConfiguration.setStartFaceOri(null);
122 CubeConfiguration.setColorMapKey(null);
123 CommandSeq.stopAsQuicklyAsPossile();
124 CommandSeq.setSolutionCommandsMatrix(null, null, 0);
125 break;
126
127 default:
128 break;
129 }
130 break;
131
132 case "CUBETOSOLVER":

Pagina 25 van 329 CubeThesis™ Depamelaere-Deschuytter


class ConsoleCommands

133 try {
134 cts.cubeToSolver();
135 } catch (NotAvailableException nae) {
136 System.err.println(nae);
137 }
138 break;
139
140 case "OPEN":
141 File f = cbthfc.fcOpenFile(1);
142 if (f != null) {
143 cbthsl.setCurrentProject(new File(f.getParent()));
144 p_vcp.updateLogFilesByFlushConsole(true, false);
145 FileIO.openProject(f);
146 }
147 break;
148
149 case "SAVE":
150 FileIO.saveProject();
151 break;
152
153 case "SAVEAS":
154 cbthfc.fcSaveFile(1);
155 break;
156
157 case "SNAPESTIM":
158 try {
159 CBTHImage img = null;
160 img = CamTakePicture.takePicture();
161 if (img != null) {
162 imgl.addCBTHImage(img);
163
164 CubeFace cf = ColorEstimation.colorRecognition(img);
165 cfl.addCubeFace(cf);
166
167 JPanel content = cf.createVCubeFace();
168
169 // Pop-up resultaat kleurherkenning igv manuele
170 // klik op knop, in automatische mode, zal de vlakKubus
171 // niet meer pop-uppen.
172 JFrame frame = cbthsl.createCubeThesisFrame("Result color-estimation...");
173 frame.add(content);
174 frame.pack();
175 frame.setVisible(true);
176 }
177 } catch (NoCaptureDevConnectionException ncdce) {
178 System.err.println(ncdce);
179 }
180 break;
181
182 case "SOLTOROBOT":
183 mstr.moveSeqToRobot();
184 break;
185
186 case "SOLVE":
187 cubie.solve();
188 break;
189
190 default:
191 break;
192 }
193 }
194
195 /**
196 * Spawns a warning-dialog to get confirmation of the user.
197 *
198 * @return The user's reaction is returned by means of an int.

Pagina 26 van 329 CubeThesis™ Depamelaere-Deschuytter


class ConsoleCommands

199 */
200 public static int showWarningMessage() {
201 String[] buttonLabels = new String[] { "Yes", "No" };
202 String defaultOption = buttonLabels[1];
203 Icon icon = null;
204
205 return JOptionPane.showOptionDialog(new JPanel(),
206 "Are you sure you want to clear all data? " + cbthsl.getString("newLine")
207 + "This operation cannot be undone when " + "the file was not saved yet.",
208 "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, icon,
209 buttonLabels, defaultOption);
210 }
211 }

Pagina 27 van 329 CubeThesis™ Depamelaere-Deschuytter


class ConsoleInputListener

1 package console;
2
3 import java.awt.event.*;
4 import javax.swing.*;
5
6 import console.ViewConsolePanel;
7 import model.CommonObjects;
8
9 /**
10 * This class receives the user's input on the commandPrompt, interprets it and
11 * puts it on the console.
12 */
13 public class ConsoleInputListener implements ActionListener {
14
15 private ViewConsolePanel vcp;
16 private static String newLine = CommonObjects.getCBTHSettingsList()
17 .getString("newLine");
18 private int officialSupCommand = -1;
19
20 public ConsoleInputListener(ViewConsolePanel vcp) {
21 this.vcp = vcp;
22 }
23
24 // Instance method:
25 /**
26 * This method is triggered every time [Enter] is hit in the commandpromptbar.
27 * Adds "&#60;: " to start the line.
28 */
29 public void actionPerformed(ActionEvent e) {
30
31 JTextField conPrompt = vcp.getCommandPrompt();
32 JTextArea conOutput = vcp.getConsole();
33 String text = conPrompt.getText();
34
35 /*
36 * The method updateRecordsCounter() will increment the counter hosted in
37 * the actual ViewConsolePanel-object. That counter takes account of both
38 * lines accepted from the commandprompt (< : ) and lines being printed by
39 * the program (> : ). By incrementing a variable, the effort is saved to
40 * count all lines in the console every time a line is printed. (speed gain
41 * purposes)
42 */
43 vcp.updateRecordsCounter();
44
45 // Check whether the limit consoleRecordsMax is not exceeded.
46 // If so, the excessive records are flushed away:
47 vcp.updateLogFilesByHysteresis();
48
49 // Check whether input is an official supported CommandFromComPrompt:
50 if ((officialSupCommand = ConsoleCommands.validCommand(text)) != -1) {
51 text = text.toUpperCase();
52 // To approve that, the text is made "uppercase".
53 }
54
55 // Adding the text to the console, before executing the tasks it might
56 // imply:
57 conOutput.append(" < : " + text + newLine);
58
59 // Executes implied tasks if the input represented a supported command:
60 if (officialSupCommand != -1) {
61 ConsoleCommands.executeCommand(officialSupCommand);
62 officialSupCommand = -1;// Reset for next input.
63 }
64
65 // Make sure the console shows the most recent text:
66 conOutput.setCaretPosition(conOutput.getDocument().getLength());

Pagina 28 van 329 CubeThesis™ Depamelaere-Deschuytter


class ConsoleInputListener

67
68 // After [Enter] the specified text is highlighted to be easily overwritten:
69 conPrompt.selectAll();
70 }
71 }

Pagina 29 van 329 CubeThesis™ Depamelaere-Deschuytter


class ConsoleOutputStream

1 package console;
2
3 import java.io.*;
4 import java.lang.StringBuffer;
5 import javax.swing.*;
6
7 import console.ViewConsolePanel;
8 import model.CommonObjects;
9
10 public class ConsoleOutputStream extends OutputStream {
11
12 private JTextArea textArea;
13 private ViewConsolePanel vcp;
14 private StringBuffer sb;
15 private static String newLine = CommonObjects.getCBTHSettingsList()
16 .getString("newLine");
17
18 // Constructor:
19 public ConsoleOutputStream(ViewConsolePanel vcv) {
20 this.vcp = vcv;
21 this.textArea = vcv.getConsole();
22 this.sb = new StringBuffer();
23 }
24
25 /*
26 * Instance methods below overwrite named alike methods from the class
27 * OutputStream. Strange enough the write(final int b)-method is obliged to
28 * implement, though never used. Only the write(byte[] b, int off, int
29 * len)-method is used & elaborated upon. This method will call for the
30 * writeToConsole(String temp)-method.
31 */
32
33 @Override
34 /**
35 * This method had to be implemented extending from the OutputStream-class,
36 * although never used.
37 */
38 public void write(final int b) throws IOException {
39
40 textArea.append(String.valueOf((char) b));
41 }
42
43 @Override
44 /**
45 * This method takes care of the usual System.out.print(ln)(); &
46 * System.err.println(); The System.out/err.println()-methods invoke this
47 * write method twice: Once to pass the actual text & once to pass an
48 * end-of-line command. The System.out.print()-method only calls once for this
49 * write method. The method was designed to be OS-independent, however it's
50 * functionality has never been tested but on Windows-computers.
51 */
52 public void write(byte[] b, int off, int len) throws IOException {
53
54 /*
55 * From the specified parameters, a String s is created. Caution: This
56 * string could represent multiple lines so possibly contains "newLine"
57 * characters.
58 */
59 String s = new String(b, off, len);
60
61 /*
62 * Unfortunately, line-separators are not OS-independent: Windows: '\r\n'
63 * "carriage return" - "line feed" etc... Mac (OS 9-): '\r' Mac (OS 10+):
64 * '\n' Unix/Linux: '\n'
65 *
66 * By making use of the CBTHSetting "newLine", instead of the character-

Pagina 30 van 329 CubeThesis™ Depamelaere-Deschuytter


class ConsoleOutputStream

67 * sequences above, this method attempts to handle the text to be printed


68 * platform-independent.
69 *
70 * The received text is buffered in a so called StringBuffer. The
71 * StringBuffer sb acts here as a Queue-structure for text: new Strings 's'
72 * are added at the end, while we delete from the start. The idea is that
73 * text being passed by means of a System.out.print() -method, is
74 * temporarily buffered till a line-end command shows up. On the other hand,
75 * one single String could imply more than one line, so we will search the
76 * StringBuffer for the occurrence of new-line- commands. A while loop will
77 * split multiple-line Strings. In both cases, text is being printed
78 * line-by-line to the console.
79 */
80 sb.append(s);
81 int newLineIndex = 0;
82
83 while (newLineIndex != -1) {
84
85 newLineIndex = sb.indexOf(newLine, 0);
86 // '0' = the index to begin the search.
87 if (newLineIndex != -1) {
88 // A line end was detected in sb.
89 writeToConsole(sb.substring(0, newLineIndex));
90 sb.delete(0, newLineIndex + newLine.length());
91 }
92 }
93 }
94
95 @Override
96 public void write(byte[] b) throws IOException {
97 write(b, 0, b.length);
98 }
99
100 /**
101 * Updates the console with new text from the out/error-streams. Will arrange
102 * the "&#62;: " symbol to start the line. This method only prints one line
103 * at a time.
104 *
105 * @param oneLine
106 * The one line text
107 */
108 public void writeToConsole(String oneLine) {
109
110 /*
111 * The method updateRecordsCounter() will increment the counter hosted in
112 * the actual ViewConsolePanel-object. That counter takes account of both
113 * lines accepted from the commandprompt (< : ) and lines being printed by
114 * the program (> : ). By incrementing a variable, the effort is saved to
115 * count all lines in the console every time a line is printed. (speed gain
116 * purposes)
117 */
118 this.vcp.updateRecordsCounter();
119
120 // Check whether a chunk of text can be flushed away according to the
121 // CBTHSettings: "consoleRecordsMin/Max":
122 this.vcp.updateLogFilesByHysteresis();
123
124 // Adding the text to the console:
125 textArea.append(" > : " + oneLine + newLine);
126
127 // Make sure the console shows the most recent text:
128 textArea.setCaretPosition(textArea.getDocument().getLength());
129 }
130 }

Pagina 31 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewConsolePanel

1 package console;
2
3 import java.awt.*;
4 import java.io.*;
5 import java.text.DateFormat;
6 import java.text.SimpleDateFormat;
7 import java.util.Date;
8 import javax.swing.*;
9 import javax.swing.text.BadLocationException;
10
11 import console.ConsoleInputListener;
12 import console.ConsoleOutputStream;
13 import model.CBTHSettingsList;
14 import model.CommonObjects;
15
16 public class ViewConsolePanel extends JPanel {
17
18 private static final long serialVersionUID = 1L;
19 public static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
20 private static final String newLine = cbthsl.getString("newLine");
21 private static int consoleRecordsMax = 500;
22 private static int consoleRecordsMin = 250;
23 private static int consoleRecordsCounter;
24
25 private JTextField commandPrompt;
26 private JTextArea console;
27 private JScrollPane scrollPane;
28
29 private PrintStream standardOut;
30 private PrintStream standardErr;
31 private ConsoleOutputStream consOutputStream;
32 private ConsoleInputListener consInputListener;
33
34 private static String fileNameLogGeneral;
35 private static String fileNameLogProj;
36
37 // Constructor:
38 public ViewConsolePanel() {
39
40 super(new BorderLayout());
41
42 updateRecordsMinMaxLimits();
43 consoleRecordsCounter = 0;
44
45 // Creation of the console & commandPrompt:
46 console = new JTextArea(4, 15);
47 commandPrompt = new JTextField(15);
48
49 console.setEditable(false);
50
51 /*
52 * For the console a 'monospaced' font is preferred, to lay out the text
53 * properly. Examples of such fonts: Lucida Console, Courier New,
54 * Consolas...
55 */
56
57 Font font = cbthsl.getFont("guiFont2");
58 console.setFont(font);
59 console.setBackground(Color.WHITE);
60 console.setForeground(Color.DARK_GRAY);
61 commandPrompt.setFont(font);
62 commandPrompt.setBackground(Color.WHITE);
63 commandPrompt.setForeground(Color.DARK_GRAY);
64 scrollPane = new JScrollPane(console,
65 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
66 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

Pagina 32 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewConsolePanel

67
68 this.add(scrollPane, BorderLayout.CENTER);
69 this.add(commandPrompt, BorderLayout.PAGE_END);
70
71 // At this point a header is written on the LogFiles.
72 fileNameLogGeneral = cbthsl
73 .makeSysIndepFilePath(new String[] { "LogFileGeneral.txt" }, 2);
74 updateLogFilesByFlushConsole(true, false);
75
76 // Organize communication user to pc: " < : "
77 consInputListener = new ConsoleInputListener(this);
78 commandPrompt.addActionListener(consInputListener);
79
80 // Organize communication pc to user: " > : "
81 consOutputStream = new ConsoleOutputStream(this);
82 PrintStream printStream = new PrintStream(consOutputStream);
83
84 // Backup of the old output/error-streams (to the console of the IDE):
85 standardOut = System.out;
86 standardErr = System.err;
87
88 /*
89 * IMPORTANT: Output- & Error-streams are redirected to the new printStream
90 * made: (If not, console won't display text)
91 */
92 try {
93 System.setOut(printStream);
94 System.setErr(printStream);
95 } catch (NullPointerException e) {
96
97 standardErr.println(e);
98 String errorMessage =
99 "ERROR: Redirecting StdOut- & " + "StdErr-stream failed."
100 + " Our apologies for the inconvenience.";
101 standardErr.println(errorMessage);
102 System.err.println(errorMessage);
103 }
104 }
105
106 // Getters:
107 public JTextField getCommandPrompt() {
108 return this.commandPrompt;
109 }
110
111 public JTextArea getConsole() {
112 return this.console;
113 }
114
115 public int getConRecordsCounter() {
116 return consoleRecordsCounter;
117 }
118
119 public PrintStream getStdErr() {
120 return standardErr;
121 }
122
123 public PrintStream getStdOut() {
124 return standardOut;
125 }
126
127 public String getTextCommandPrompt() {
128 return commandPrompt.getText();
129 }
130
131 // Setter:
132 /**

Pagina 33 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewConsolePanel

133 * Used by the commands menu to drop the selected text in the
134 * commandprompt-bar.
135 */
136 public void setTextCommandPrompt(String text) {
137 commandPrompt.setText(text);
138 }
139
140 // Instance methods, listed alphabetically:
141 public void clearConsole() {
142
143 console.setText("");
144 }
145
146 /**
147 * This method flushes all the text available in the console to the logFiles.
148 * By option, a header or footer could be written to the logFiles.
149 * Open_Project uses this as well to make sure the new project's logFile
150 * contains no info of a former opened project. The MenuItem "Flush and Clear"
151 * also uses this method.
152 *
153 * @param header
154 * Should a header be written to the logFiles?
155 * @param footer
156 * Should a footer be written to the logFiles?
157 */
158 public void updateLogFilesByFlushConsole(boolean header, boolean footer) {
159
160 String[] pathComponents = {
161 "LogFile" + cbthsl.getCurrentProject().getName() + ".txt" };
162 fileNameLogProj = cbthsl.makeSysIndepFilePath(pathComponents, 3);
163
164 // Write header:
165 if (header) {
166
167 String[][] logFileNames = { { fileNameLogGeneral }, { fileNameLogProj } };
168
169 // Make sure the LogFileGeneral.txt updates:
170 writeToLogFiles(logFileNames[0],
171 newLine + newLine + createHeaderText(null) + newLine);
172 // Make sure the LogFileProject.txt updates:
173 writeToLogFiles(logFileNames[1], newLine + newLine
174 + createHeaderText(cbthsl.getCurrentProject().getName()) + newLine);
175 }
176
177 // Flush remaining data from console, if flushing makes sense:
178 if (console.getLineCount() > 0) {
179
180 writeToLogFiles(new String[] { fileNameLogGeneral, fileNameLogProj },
181 console.getText());
182
183 clearConsole();
184 consoleRecordsCounter = 0;
185 }
186
187 // Write footer:
188 if (footer) {
189 writeToLogFiles(new String[] { fileNameLogGeneral, fileNameLogProj },
190 newLine + createFooterText());
191 }
192 }
193
194 /**
195 * Every line added to the console calls for updateLogFilesByHysteresis. This
196 * method will check itself whether flushing is needed according to the
197 * consoleRecordsMin/Max-limits. At the end it will check for new
198 * consoleRecordsMin/Max-limits.

Pagina 34 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewConsolePanel

199 */
200 public void updateLogFilesByHysteresis() {
201
202 fileNameLogProj = null;
203
204 if (consoleRecordsCounter > consoleRecordsMax) {
205
206 String[] pathComponents = {
207 "LogFile" + cbthsl.getCurrentProject().getName() + ".txt" };
208 fileNameLogProj = cbthsl.makeSysIndepFilePath(pathComponents, 3);
209
210 try {
211 /* The exact nmbrOfLinesToBeDeleted is calculated. */
212 int nmbrOfLinesToBeDeleted = console.getLineCount() - consoleRecordsMin;
213 int lineStartOffset = console.getLineStartOffset(nmbrOfLinesToBeDeleted);
214 standardOut.println("nmbrOfLinesToBeDeleted: " + nmbrOfLinesToBeDeleted);
215 standardOut.println("posOfLastLine: " + lineStartOffset);
216
217 writeToLogFiles(new String[] { fileNameLogGeneral, fileNameLogProj },
218 console.getText(0, lineStartOffset));
219
220 // First lines are replaced by an empty String:
221 console.replaceRange("", 0, lineStartOffset);
222
223 /*
224 * Counter is updated. Note this takes place within the try{}catch(){},
225 * so if an error might occur, the counter will not be updated.
226 */
227 consoleRecordsCounter = consoleRecordsMin;
228
229 } catch (BadLocationException ex) {
230 System.err.println("ERROR: " + ex);
231 }
232 /*
233 * Maybe these consoleRecorsMin/Max need an update from the CBTHSettings.
234 * NOTE: These are only updated when the if(){} above gets triggered using
235 * old parameters.
236 */
237 updateRecordsMinMaxLimits();
238 }
239 }
240
241 /**
242 * The consoleRecordsCounter is incremented when a new line is being added.
243 * Checking this counter (to determine wheter a flush is required), saves the
244 * effort of counting all the lines in the console each time a new line is
245 * added. The counter is reset after a flush.
246 */
247 public void updateRecordsCounter() {
248
249 consoleRecordsCounter++;
250 }
251
252 /**
253 * Updates the hysteresis record-limits of the console by the respective
254 * CBTHSettings if those make sense.
255 */
256 public void updateRecordsMinMaxLimits() {
257
258 int a = cbthsl.getInt("consoleRecordsMax");
259 int b = cbthsl.getInt("consoleRecordsMin");
260
261 if (a > b && b >= 0) {
262 consoleRecordsMax = a;
263 consoleRecordsMin = b;
264 }

Pagina 35 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewConsolePanel

265 }
266
267 /**
268 * This method will implement the actual writing to the logFiles.
269 *
270 * @param logFileNames
271 * To which fileNames is to be written
272 * @param text
273 * This text is written to the specified files.
274 */
275 public static void writeToLogFiles(String[] logFileNames, String text) {
276 FileWriter fw = null;
277 PrintWriter pw = null;
278
279 for (int i = 0; i < logFileNames.length; i++) {
280
281 if (logFileNames[i] != null && logFileNames[i] != ""
282 && logFileNames[i].endsWith(".txt")) {
283
284 try {
285
286 /*
287 * Writer objects are declared and initialized. "true" stands for
288 * appending to the original content, rather than overriding it.
289 */
290 fw = new FileWriter(logFileNames[i], true);
291 pw = new PrintWriter(fw);
292
293 /*
294 * Text is printed, and the writers are flushed to make sure no text
295 * remains in temporary buffers.
296 */
297 pw.print(text);
298 pw.flush();
299
300 } catch (IOException ioe) {
301 System.err.println(
302 "ERROR: An IOException occurred " + "during writing to LogFiles.");
303 for (StackTraceElement ste : ioe.getStackTrace()) {
304 System.err.println("STACKTRACE: " + ste);
305 }
306 ;
307 }
308
309 finally {
310 // Elaborated closing-procedure, allowing for
311 // IOExceptions due to closing:
312 if (pw != null) {
313 pw.close();
314 } else {
315 if (fw != null) {
316 try {
317 fw.close();
318 } catch (IOException ioe) {
319 System.err.println(
320 "ERROR: An IOException occurred during closing of FileWriter "
321 + "after writing to LogFiles.");
322 }
323 }
324 }
325 }
326 }
327 }
328 }
329
330 /*

Pagina 36 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewConsolePanel

331 * Static methods: They do not directly affect the object, but mostly perform
332 * other useful tasks. One could literally speak of "outsourcing tasks" - with
333 * stress on "source" - to auxillary methods.
334 */
335
336 /**
337 * This method provides footertext for the logFiles.
338 *
339 * @return The footer is returned by means of a String.
340 */
341 public static String createFooterText() {
342 String footer = null;
343
344 // Fetch current date/time for footer:
345 DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
346 String dateFooter = dateFormat.format(new Date());
347 String footerStatement = "* © CubeThesis was exited at: " + dateFooter + " *";
348 String amntOfStripes = signToSequence("–", footerStatement.length());
349
350 // Assembling the footer:
351 footer = amntOfStripes + newLine + footerStatement + newLine + amntOfStripes;
352
353 return footer;
354 }
355
356 /**
357 * createHeaderText, will create a projectName-dependent header for the
358 * logFiles.
359 *
360 * @param projectName
361 * Name of the current CBTHProject. (Available in the CBTHSettings)
362 * @return Header as a String-object.
363 */
364 public static String createHeaderText(String projectName) {
365
366 String header = null;
367 String projectDesignation = null;
368
369 if (projectName != null) {
370 projectDesignation = "PROJECT: " + projectName;
371 } else {
372 projectDesignation = "GENERAL";
373 }
374
375 // Fetch current date/time for header:
376 DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
377 String dateHeader = dateFormat.format(new Date());
378 String surroundingSign = "=";
379
380 // Title is presumed to be longer than the subtitle,
381 // since additional spaces are added to the subtitle.
382 String title = surroundingSign + " LOGFILE " + projectDesignation
383 + " © CubeThesis 2015-2016 Deschuytter Simon & Depamelaere Pieter "
384 + surroundingSign;
385 String subTitle = surroundingSign + " CubeThesis(-project) was started at: ";
386 String amountOfSpaces = signToSequence(" ",
387 title.length() - subTitle.length() - dateHeader.length() - 1);
388 String amntOfSurroundngSgn = signToSequence(surroundingSign, title.length());
389
390 header = amntOfSurroundngSgn + newLine + title + newLine + subTitle + dateHeader
391 + amountOfSpaces + surroundingSign + newLine + amntOfSurroundngSgn;
392
393 return header;
394 }
395
396 /**

Pagina 37 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewConsolePanel

397 * Returns a given sign a specified number of times.


398 *
399 * @param sign
400 * The sign, character that is to be repeated.
401 * @param amount
402 * Number of times the sign must be repeated.
403 * @return A String, being the sequence of the repeated sign.
404 */
405 public static String signToSequence(String sign, int amount) {
406
407 String signSequence = sign;// Do this once in advance,
408 // otherwise null is printed.
409
410 for (int am = 0; am < amount - 1; am++) {
411 signSequence += sign;
412 }
413 return signSequence;
414 }
415 }

Pagina 38 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeletAlreadyAssignedException

1 package exceptions;
2
3 import model.CBTHSettingsList;
4 import model.CommonObjects;
5
6 public class CubeletAlreadyAssignedException extends Exception {
7
8 /*
9 * The first attribute serialVersionUID is a recommended attribute when
10 * "extending", however of no real importance.
11 */
12 private static final long serialVersionUID = 1L;
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14 private int cubeletID;
15 private String cubeletColors;
16 private String colorsLocation1;
17 private String colorsLocation2;
18
19 // Constructors:
20 public CubeletAlreadyAssignedException() {
21 super();
22 this.cubeletID = -1;
23 this.cubeletColors = null;
24 this.colorsLocation1 = null;
25 this.colorsLocation2 = null;
26 }
27
28 public CubeletAlreadyAssignedException(int cubeletID, String cubeletColors,
29 String colorsLocation1, String colorsLocation2) {
30 super();
31 this.cubeletID = cubeletID;
32 this.cubeletColors = cubeletColors;
33 this.colorsLocation1 = colorsLocation1;
34 this.colorsLocation2 = colorsLocation2;
35 }
36
37 @Override
38 public String toString() {
39 return "ERROR: Cubelet \"" + cubeletID + "\" with faceletcolors "
40 + cubeletColors
41 + " was identified twice or more. The issue "
42 + "occurred at the locations below:"
43 + cbthsl.getString("newLine") + "ERROR: " + colorsLocation1 + " & "
44 + colorsLocation2
45 + " (both expressed by the facelet colors of the cubelet that "
46 + "belongs there in solved cubestate.)" + cbthsl.getString("newLine")
47 + "ERROR: Attention to the errorlocations when middle-cubelets "
48 + "are involved: they're expressed without recolouring. "
49 + "Our apologies for the inconvenience. ";
50 }
51 }

Pagina 39 van 329 CubeThesis™ Depamelaere-Deschuytter


class FaceletColorNoneException

1 package exceptions;
2
3 import model.CBTHSettingsList;
4 import model.CommonObjects;
5
6 public class FaceletColorNoneException extends Exception {
7
8 private static final long serialVersionUID = 1L;
9 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
10 private String mainCubeFaceName;
11 private int row;
12 private int column;
13
14 // Constructors:
15 public FaceletColorNoneException() {
16 super();
17 this.mainCubeFaceName = null;
18 this.row = -1;
19 this.column = -1;
20 }
21
22 public FaceletColorNoneException(String mainCubeFaceName, int row, int column) {
23 super();
24 this.mainCubeFaceName = mainCubeFaceName;
25 this.row = row;
26 this.column = column;
27 }
28
29 @Override
30 public String toString() {
31 return "ERROR: Main-cubeface \"" + mainCubeFaceName
32 + "\" reports a facelet at [row, column]: [" + row + ", " + column
33 + "] to be colorless." + cbthsl.getString("newLine")
34 + "ERROR: With not all faceletcolors differing from \""
35 + cbthsl.translateColorsIntToString(6)
36 + "\", CubeThesis won't achieve a virtual cube configuration."
37 + cbthsl.getString("newLine")
38 + "ERROR: Our apologies for the inconvenience.";
39 }
40 }

Pagina 40 van 329 CubeThesis™ Depamelaere-Deschuytter


class NoCaptureDevConnectionException , NoImageForColorEstimationException

1 package exceptions;
2
3 public class NoCaptureDevConnectionException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6
7 // Constructor:
8 public NoCaptureDevConnectionException() {
9 super();
10 }
11
12 @Override
13 public String toString() {
14 return "[CAMLINK]: ERROR: Connection with CaptureDevice wasn't "
15 + "established. Our apologies for the inconvencience.";
16 }
17 }

1 package exceptions;
2
3 public class NoImageForColorEstimationException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6
7 // Constructor:
8 public NoImageForColorEstimationException() {
9 super();
10 }
11
12 @Override
13 public String toString() {
14 return "ERROR: There is no image available to apply color-estimation. "
15 + "Our apologies for the inconvenience.";
16 }
17 }

Pagina 41 van 329 CubeThesis™ Depamelaere-Deschuytter


class NoMatchingSettingTypeException

1 package exceptions;
2
3 public class NoMatchingSettingTypeException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6 private String settingName;
7 private String receivedType;
8 private String expectedType;
9
10 // Constructors:
11 public NoMatchingSettingTypeException() {
12 super();
13 this.settingName = null;
14 this.receivedType = null;
15 this.expectedType = null;
16 }
17
18 public NoMatchingSettingTypeException(String settingName, String receivedType,
19 String expectedType) {
20 super();
21 this.settingName = settingName;
22 this.receivedType = receivedType;
23 this.expectedType = expectedType;
24 }
25
26 @Override
27 public String toString() {
28
29 return "ERROR: \"" + settingName + "\": Settingtypes don't match. Received: ["
30 + receivedType + "], while [" + expectedType
31 + "] expected. Our apologies for the inconvenience.";
32 }
33 }

Pagina 42 van 329 CubeThesis™ Depamelaere-Deschuytter


class NonExistingCubeletException

1 package exceptions;
2
3 import model.CBTHSettingsList;
4 import model.CommonObjects;
5
6 public class NonExistingCubeletException extends Exception {
7
8 private static final long serialVersionUID = 1L;
9 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
10 private int[] notExistingColors;
11 private int[] colorsLocation;
12
13 // Constructors:
14 public NonExistingCubeletException() {
15 this.notExistingColors = null;
16 this.colorsLocation = null;
17 }
18
19 public NonExistingCubeletException(int[] notExistingColors, int[] colorsLocation) {
20 this.notExistingColors = notExistingColors;
21 this.colorsLocation = colorsLocation;
22 }
23
24 @Override
25 public String toString() {
26
27 StringBuffer sb = new StringBuffer();
28 sb.append("ERROR: On a official cube, there is no cubelet "
29 + "available with faceletcolors [");
30 int i = 0;
31
32 while (i < notExistingColors.length - 1) {
33 sb.append(cbthsl.translateColorsIntToString(notExistingColors[i]) + ", ");
34 i++;
35 }
36 sb.append(cbthsl.translateColorsIntToString(notExistingColors[i])
37 + "]. The issue occurred at the location below: [");
38
39 i = 0;
40 while (i < colorsLocation.length - 1) {
41 sb.append(cbthsl.translateColorsIntToString(colorsLocation[i]) + ", ");
42 i++;
43 }
44
45 sb.append(cbthsl.translateColorsIntToString(colorsLocation[i]) + "].");
46 sb.append(cbthsl.getString("newLine")
47 + "ERROR: (Expressed by the facelet colors of the cubelet "
48 + "that belongs there in solved cubestate.) Our apologies for "
49 + "the inconvenience.");
50
51 return sb.toString();
52 }
53 }

Pagina 43 van 329 CubeThesis™ Depamelaere-Deschuytter


class NoSuchSettingFoundException , NotAvailableException

1 package exceptions;
2
3 public class NoSuchSettingFoundException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6 private String nameSetting;
7
8 // Constructor:
9 public NoSuchSettingFoundException(String nameSetting) {
10 super();
11 this.nameSetting = nameSetting;
12 }
13
14 @Override
15 public String toString() {
16 return "ERROR: Attempt to reach for unexisting setting: \"" + nameSetting
17 + "\". Our apologies for the inconvenience.";
18 }
19 }

1 package exceptions;
2
3 public class NotAvailableException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6 private String subject;
7 private String solution;
8
9 // Constructors:
10 public NotAvailableException() {
11 super();
12 this.subject = null;
13 this.solution = null;
14 }
15
16 public NotAvailableException(String subject, String solution) {
17 super();
18 this.subject = subject;
19 this.solution = solution;
20 }
21
22 @Override
23 public String toString() {
24 return "ERROR: There's no (vaild) \"" + subject
25 + "\" available. Our apologies for the inconvenience. " + solution;
26 }
27 }

Pagina 44 van 329 CubeThesis™ Depamelaere-Deschuytter


class NotIntendedIPAddressException , NoValidFileException

1 package exceptions;
2
3 public class NotIntendedIPAddressException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6 private String actualIPAddress;
7 private String intendedIPAddress;
8 private String deviceType;
9
10 // Constructor:
11 public NotIntendedIPAddressException(String actualIPAddress, String deviceType,
12 String intendedIPAddress) {
13 this.actualIPAddress = actualIPAddress;
14 this.intendedIPAddress = intendedIPAddress;
15 this.deviceType = deviceType;
16 }
17
18 @Override
19 public String toString() {
20 return "ERROR: Actual IP-address of " + deviceType + ": \"" + actualIPAddress
21 + "\" does not match intended address: \"" + intendedIPAddress
22 + "\". Our apologies for the inconvencience.";
23 }
24 }

1 package exceptions;
2
3 public class NoValidFileException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6 private String fileType;
7
8 // Constructors:
9 public NoValidFileException() {
10 super();
11 this.fileType = null;
12 }
13
14 public NoValidFileException(String fileType) {
15 super();
16 this.fileType = fileType;
17 }
18
19 @Override
20 public String toString() {
21 return "ERROR: There was no valid \"" + fileType
22 + "\"-file selected. Our apologies for the inconvenience.";
23 }
24
25 }

Pagina 45 van 329 CubeThesis™ Depamelaere-Deschuytter


class NumberNotFoundException , WorkInProgressException

1 package exceptions;
2
3 public class NumberNotFoundException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6 private String errorMessageTail;
7
8 // Constructors:
9 public NumberNotFoundException() {
10 super();
11 this.errorMessageTail = null;
12 }
13
14 public NumberNotFoundException(String errorMessageTail) {
15 super();
16 this.errorMessageTail = errorMessageTail;
17 }
18
19 @Override
20 public String toString() {
21 return "ERROR: Number wasn't found in " + errorMessageTail
22 + ". Our apologies for the inconvenience.";
23 }
24
25 }

1 package exceptions;
2
3 public class WorkInProgressException extends Exception {
4
5 private static final long serialVersionUID = 1L;
6 private String errorMessage;
7
8 // Constructors:
9 public WorkInProgressException() {
10 super();
11 this.errorMessage = null;
12 }
13
14 public WorkInProgressException(String errorMessage) {
15 super();
16 this.errorMessage = errorMessage;
17 }
18
19 @Override
20 public String toString() {
21 return "[WIP] " + errorMessage + "will not function properly yet. "
22 + "Our apologies for the inconvenience.";
23 }
24 }

Pagina 46 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_AUT_AutomaticRoutineListener

1 package listeners.aut;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5
6 import model.AutomaticRoutine;
7 import model.CBTHImagesList;
8 import model.CubeFacesList;
9 import view.ViewTabPanel4Aut;
10
11 public class B_AUT_AutomaticRoutineListener implements ActionListener {
12
13 private AutomaticRoutine autoRoutineThread;
14 private CBTHImagesList imgl;
15 private CubeFacesList cfl;
16 private ViewTabPanel4Aut vtpa;
17
18 // Constructor:
19 public B_AUT_AutomaticRoutineListener(CBTHImagesList imgl, CubeFacesList cfl,
20 ViewTabPanel4Aut vtpa) {
21 this.imgl = imgl;
22 this.cfl = cfl;
23 this.vtpa = vtpa;
24 }
25
26 /*
27 * Instance method: Implementing an ActionListener, this class should provide
28 * an actionPerformed(ActionEvent e)-method. This method will react on the
29 * JButton.
30 */
31 public void actionPerformed(ActionEvent e) {
32
33 // If a previous thread is running, try to stop it:
34 if (autoRoutineThread != null) {
35 try {
36 AutomaticRoutine.setRoutineNotAborted(false);
37 autoRoutineThread.join();
38 } catch (InterruptedException ie) {
39 System.err.println("ERROR: Interrupted exception occurred. "
40 + "Our apologies for the inconvenience.");
41 }
42 }
43
44 System.out.println("Automatic routine started...");
45
46 autoRoutineThread = new AutomaticRoutine(imgl, cfl, vtpa);
47 AutomaticRoutine.setRoutineNotAborted(true);
48 autoRoutineThread.start();
49 }
50 }

Pagina 47 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_AUT_CommandToRobotListener , B_AUT_StopAutoRoutineListener

1 package listeners.aut;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.JOptionPane;
6
7 import model.CBTHSettingsList;
8 import model.CommandSeq;
9 import model.CommonObjects;
10
11 public class B_AUT_CommandToRobotListener implements ActionListener {
12
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14
15 // Constructor:
16 public B_AUT_CommandToRobotListener() {
17 super();
18 }
19
20 // Instance method:
21 public void actionPerformed(ActionEvent e) {
22 String move = null;
23 try {
24 move = (String) JOptionPane.showInputDialog(null,
25 "Which cube(-reading/-solving) move is to be performed? "
26 + "Enter an integer number...",
27 "Manually add move to robot's queue...", JOptionPane.QUESTION_MESSAGE, null,
28 null, "3");
29 CommandSeq.addNewCommand(Integer.parseInt(move));
30 } catch (NumberFormatException nfe) {
31 CommandSeq.addNewCommand(cbthsl.getInt("noValidCommand"));
32 }
33 }
34 }

1 package listeners.aut;
2
3 import java.awt.event.ActionListener;
4 import java.awt.event.ActionEvent;
5
6 import model.AutomaticRoutine;
7 import model.CommandSeq;
8
9 public class B_AUT_StopAutoRoutineListener implements ActionListener {
10
11 // Constructor:
12 public B_AUT_StopAutoRoutineListener() {
13 super();
14 }
15
16 // Instance method:
17 public void actionPerformed(ActionEvent e) {
18 // Robot will stop as quickly as possible from the Java-software
19 // by throwing away it's queue.
20 CommandSeq.stopAsQuicklyAsPossile();
21
22 // AutomaticRoutine will discard its tasks:
23 AutomaticRoutine.setRoutineNotAborted(false);
24
25 }
26 }

Pagina 48 van 329 CubeThesis™ Depamelaere-Deschuytter


class T_AUT_SubTasksItemListener

1 package listeners.aut;
2
3 import java.awt.event.ItemListener;
4 import java.awt.event.ItemEvent;
5
6 import model.AutomaticRoutine;
7
8 public class T_AUT_SubTasksItemListener implements ItemListener {
9
10 private int indexBooleanToWatch;
11
12 // Constructor:
13 public T_AUT_SubTasksItemListener(int indexBooleanToWatch) {
14 this.indexBooleanToWatch = indexBooleanToWatch;
15 }
16
17 /*
18 * Implementing an ItemListener, this class should provide an
19 * itemStateChanged(ItemEvent e)-method. This method will 'react' on the
20 * JToggleButton.
21 */
22 public void itemStateChanged(ItemEvent e) {
23 if (e.getStateChange() == ItemEvent.SELECTED) {
24 AutomaticRoutine.setSubTaskNecessary(indexBooleanToWatch, true);
25 } else {
26 AutomaticRoutine.setSubTaskNecessary(indexBooleanToWatch, false);
27 }
28 }
29 }

Pagina 49 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CAM_ConnectCamListener , B_CAM_ConnectRobotListener

1 package listeners.cam;
2
3 import java.awt.event.*;
4 import javax.swing.JOptionPane;
5
6 import model.CBTHSettingsList;
7 import model.CommonObjects;
8
9 public class B_CAM_ConnectCamListener implements ActionListener {
10
11 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
12
13 // Constructor:
14 public B_CAM_ConnectCamListener() {
15 super();
16 }
17
18 // Instance method:
19 public void actionPerformed(ActionEvent e) {
20 String camName = null;
21 camName = (String) JOptionPane.showInputDialog(null,
22 "Enter a number/name to specify the camera to be used:",
23 "Specify your capture device...", JOptionPane.QUESTION_MESSAGE, null, null, "0");
24 cbthsl.setString("captureDevice", camName);
25 }
26 }

1 package listeners.cam;
2
3 import java.awt.event.*;
4
5 import connection.conWithRobot.CommunicationRobotThread;
6 import model.CommonObjects;
7
8 public class B_CAM_ConnectRobotListener implements ActionListener {
9
10 // Constructor:
11 public B_CAM_ConnectRobotListener() {
12 super();
13 }
14
15 // Instance method:
16 public void actionPerformed(ActionEvent e) {
17
18 CommunicationRobotThread comRobot = CommonObjects.getCommunicatieRobot();
19 if (!comRobot.isAlive()) {
20 // "isAlive()" is a standard threadinstance-method
21 // to check whether it's running.
22 comRobot.start();
23 }
24 comRobot.initializeCommunicationRobot();
25 }
26 }

Pagina 50 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CAM_TakeAPictureListener

1 package listeners.cam;
2
3 import java.awt.event.*;
4
5 import connection.conWithCamera.CamTakePicture;
6 import exceptions.NoCaptureDevConnectionException;
7 import model.CBTHImage;
8 import model.CBTHImagesList;
9
10 public class B_CAM_TakeAPictureListener implements ActionListener {
11
12 private CBTHImagesList imgl;
13
14 // Constructor:
15 public B_CAM_TakeAPictureListener(CBTHImagesList imgl,
16 T_CAM_LiveStreamItemListener lsil) {
17 this.imgl = imgl;
18 new CamTakePicture(lsil);
19 }
20
21 // Instance method:
22 public void actionPerformed(ActionEvent e) {
23 try {
24 CBTHImage img = null;
25 img = CamTakePicture.takePicture();
26 if (img != null) {
27 imgl.addCBTHImage(img);
28 }
29 } catch (NoCaptureDevConnectionException ncdce) {
30 System.err.println(ncdce);
31 }
32 }
33 }

Pagina 51 van 329 CubeThesis™ Depamelaere-Deschuytter


class T_CAM_LiveStreamItemListener

1 package listeners.cam;
2
3 import java.awt.event.*;
4 import java.awt.image.BufferedImage;
5 import javax.swing.*;
6
7 import org.opencv.core.Core;
8 import org.opencv.videoio.VideoCapture;
9 import org.opencv.videoio.Videoio;
10
11 import connection.conWithCamera.*;
12 import exceptions.NoCaptureDevConnectionException;
13 import model.CBTHSettingsList;
14 import model.CommonObjects;
15
16 public class T_CAM_LiveStreamItemListener implements ItemListener {
17
18 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
19 private JLabel l_CamView;
20 private CamLiveStreamThread clsThread;
21 private VideoCapture cam;
22 private Thread t;
23 private boolean linkCamEstablished;
24
25 // Constructor:
26 public T_CAM_LiveStreamItemListener(JLabel l_CamView) {
27 this.l_CamView = l_CamView;
28 this.linkCamEstablished = false;
29 }
30
31 // Getters:
32 public int getCapDeviceFrameHeight() {
33
34 int value = 0;
35 if (cam.isOpened() && cam != null) {
36 value = (int) cam.get(Videoio.CAP_PROP_FRAME_WIDTH);
37 }
38 return value;
39 }
40
41 public int getCapDeviceFrameWidth() {
42
43 int value = 0;
44 if (cam.isOpened() && cam != null) {
45 value = (int) cam.get(Videoio.CAP_PROP_FRAME_WIDTH);
46 }
47 return value;
48 }
49
50 public BufferedImage getCurrentFrame() throws NoCaptureDevConnectionException {
51 BufferedImage frame = null;
52
53 if (linkCamEstablished) {
54 frame = clsThread.getCurrentFrame();
55 }
56
57 else {
58 throw new NoCaptureDevConnectionException();
59 }
60 return frame;
61 }
62
63 public boolean getLinkCamEstablished() {
64 return linkCamEstablished;
65 }
66

Pagina 52 van 329 CubeThesis™ Depamelaere-Deschuytter


class T_CAM_LiveStreamItemListener

67 // Instance methods:
68 public void connectToCapDevice() {
69
70 try {
71 // Happens when the livestream-button is hit:
72
73 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
74
75 // Creation of the VideoCapture-object.
76 cam = new VideoCapture();
77 String capDeviceName = cbthsl.getString("captureDevice");
78 int capDeviceIndex = 0;
79 linkCamEstablished = false;
80
81 /*
82 * The CBTHSetting captureDevice is of the type String an not int because
83 * it was made ready to contain a full ip-adres to reach the camdevice.
84 * However this was not succeeded, so the cam is reached by it's device
85 * index. possible indexes 0 or 700, 1 or 701, ...
86 *
87 * (Port used by CAMERA 3956 <= learned from WireSharksoftware)
88 */
89 try {
90 /*
91 * At first, we try to reach the cam by its index. To do so, the
92 * capDeviceName is converted to a number if a NumberFormatException
93 * would occur, meaning that the capDeviceName is not a number, we try
94 * later on to open it by it's String name.
95 */
96
97 capDeviceIndex = Integer.parseInt(capDeviceName);
98 cam.open(capDeviceIndex);
99
100 } catch (NumberFormatException nfe) {
101
102 /*
103 * Another attempt to reach for the cam, using its capDeviceName as a
104 * String.
105 */
106
107 cam.open(capDeviceName);
108 }
109
110 if (cam.isOpened()) {
111 System.out.println("[CAMLINK]: Link to \"" + cam.toString()
112 + "\" as capture-device was established properly.");
113 linkCamEstablished = true;
114 l_CamView.setText("");
115 clsThread = new CamLiveStreamThread(cam, l_CamView);
116 t = new Thread(clsThread, "CBTH: Camera-stream.");
117
118 /*
119 * The Java Virtual Machine (JVM) only stops if all user-threads have
120 * finished. "daemon"="spook" means the thread is running in the
121 * background. Mr. Michiel Willocx told us this is not quite necessary.
122 */
123
124 // t.setDaemon(true);
125
126 clsThread.runnable = true;
127 t.start();
128 } else {
129 String newLine = cbthsl.getString("newLine");
130 System.err.println("[CAMLINK]: ERROR: Selected capture device couldn't be opened."
131 + newLine + "[CAMLINK]: Hint: Make sure prior to booting "
132 + "CubeThesis, \"IC-Capture\" was started and shut down again." + newLine

Pagina 53 van 329 CubeThesis™ Depamelaere-Deschuytter


class T_CAM_LiveStreamItemListener

133 + "[CAMLINK]: Hint: IC-Capture should at least be able "


134 + "to retrieve the cam's output, if not, check the " + "ethernet-connection."
135 + newLine + "[CAMLINK]: Hint: Working on "
136 + "a laptop, external power-supply could be required to "
137 + "retrieve frames from gigabit-connection." + newLine
138 + "[CAMLINK]: Hint: Alter the capture device index in "
139 + "CubeThesis. See [CamConnection/CBTHSettings].");
140 }
141
142 } catch (Exception exp) {
143 System.err.println("[CAMLINK]: ERROR: Some unexpected error occurred.");
144 exp.printStackTrace();
145 }
146 }
147
148 public void disconnectFromCapDevice() {
149 if (clsThread != null) {
150 clsThread.runnable = false;
151 }
152
153 if (cam.isOpened() && cam != null) {
154 cam.release();
155 }
156
157 linkCamEstablished = false;
158 }
159
160 /*
161 * Implementing an ItemListener, this class should provide an
162 * itemStateChanged(ItemEvent e)-method. This method will 'react' on the
163 * JToggleButton.
164 */
165 public void itemStateChanged(ItemEvent e) {
166 if (e.getStateChange() == ItemEvent.SELECTED) {
167 connectToCapDevice();
168 } else {
169 if (e.getStateChange() == ItemEvent.DESELECTED) {
170 disconnectFromCapDevice();
171 }
172 }
173 }
174 }package listeners.cbthsettings;
175
176 import java.awt.event.ActionEvent;
177 import java.awt.event.ActionListener;
178
179 import model.CBTHSettingsList;
180 import model.CommonObjects;
181
182 public class MenuItemSortListener implements ActionListener {
183
184 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
185 private int sortingCriterion;
186
187 // Constructor:
188 public MenuItemSortListener(int sortingCriterion) {
189
190 this.sortingCriterion = sortingCriterion;
191 }
192
193 // Instance method:
194 public void actionPerformed(ActionEvent e) {
195 cbthsl.sortCBTHSettings(sortingCriterion);
196 }
197 }

Pagina 54 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemSortListener r

1 package listeners.cbthsettings;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5
6 import model.CBTHSettingsList;
7 import model.CommonObjects;
8
9 public class MenuItemSortListener implements ActionListener {
10
11 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
12 private int sortingCriterion;
13
14 // Constructor:
15 public MenuItemSortListener(int sortingCriterion) {
16
17 this.sortingCriterion = sortingCriterion;
18 }
19
20 // Instance method:
21 public void actionPerformed(ActionEvent e) {
22 cbthsl.sortCBTHSettings(sortingCriterion);
23 }
24 }

Pagina 55 van 329 CubeThesis™ Depamelaere-Deschuytter


class TF_SettingsCustomizerDocumentListener

1 package listeners.cbthsettings;
2
3 import javax.swing.event.DocumentEvent;
4 import javax.swing.event.DocumentListener;
5 import javax.swing.JTextField;
6
7 import model.CBTHSettingsList;
8 import model.CommonObjects;
9
10 public class TF_SettingsCustomizerDocumentListener implements DocumentListener {
11
12 private static CBTHSettingsList cbthsl;
13 private JTextField tf_TextFieldToWatch;
14
15 // Constructor:
16 public TF_SettingsCustomizerDocumentListener(JTextField tf_textFieldToWatch) {
17
18 // Source: http://stackoverflow.com/questions/3953208/
19 // value-change-listener-to-jtextfield On 28/03/2016.
20 cbthsl = CommonObjects.getCBTHSettingsList();
21 this.tf_TextFieldToWatch = tf_textFieldToWatch;
22 }
23
24 // Instance methods:
25 public void changedUpdate(DocumentEvent e) {
26 update();
27 }
28
29 public void removeUpdate(DocumentEvent e) {
30 update();
31 }
32
33 public void insertUpdate(DocumentEvent e) {
34 update();
35 }
36
37 public void update() {
38 cbthsl.filterSettingsOnTextFragment(tf_TextFieldToWatch.getText());
39 }
40 }

Pagina 56 van 329 CubeThesis™ Depamelaere-Deschuytter


class TF_VisualCBTHSettingListener

1 package listeners.cbthsettings;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5
6 import model.CBTHSetting;
7 import view.VisualCBTHSetting;
8
9 public class TF_VisualCBTHSettingListener implements ActionListener {
10
11 private CBTHSetting cbths;
12 private VisualCBTHSetting visualCBTHS;
13
14 // Constructors:
15 public TF_VisualCBTHSettingListener() {
16 this.cbths = null;
17 this.visualCBTHS = null;
18 }
19
20 public TF_VisualCBTHSettingListener(CBTHSetting cbths, VisualCBTHSetting visualCBTHS) {
21 this.cbths = cbths;
22 this.visualCBTHS = visualCBTHS;
23 }
24
25 // Instance method:
26 public void actionPerformed(ActionEvent e) {
27 cbths.setAll(null, null, null, visualCBTHS.getTF_CBTHSValue().getText(), null);
28 }
29 }

Pagina 57 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CUBE_AssignToMainCubeFaceListener

1 package listeners.cube;
2
3 import java.awt.event.*;
4
5 import model.CubeFace;
6 import view.ViewTabPanel2Cub;
7
8 public class B_CUBE_AssignToMainCubeFaceListener implements ActionListener {
9
10 private ViewTabPanel2Cub vtpc;
11
12 // Constructor:
13 public B_CUBE_AssignToMainCubeFaceListener(ViewTabPanel2Cub vtpc) {
14 this.vtpc = vtpc;
15 }
16
17 // Instance method:
18 public void actionPerformed(ActionEvent e) {
19
20 CubeFace cf = null, mcf = null;
21
22 mcf = vtpc.getSelectedMainCubeFaceFromCombo();
23 cf = vtpc.getCurrentCubeFace();
24
25 if (cf != null && mcf != null) {
26 mcf.setCubeFaceDeepCopy(cf.getColorsMatrix(), cf.getConfidenceMatrix());
27 vtpc.cubeFacePanelUpUpdate(mcf);
28 System.out.println("MainCubeFace \"" + mcf.toString() + "\" was updated.");
29 }
30 }
31 }

Pagina 58 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CUBE_BuildVirtualCubeListener

1 package listeners.cube;
2
3 import java.awt.event.*;
4
5 import exceptions.CubeletAlreadyAssignedException;
6 import exceptions.FaceletColorNoneException;
7 import exceptions.NonExistingCubeletException;
8 import model.CubeConfiguration;
9 import model.CubeFace;
10 import model.CubeFacesList;
11
12 public class B_CUBE_BuildVirtualCubeListener implements ActionListener {
13
14 private CubeFacesList cfl;
15
16 // Constructor:
17 public B_CUBE_BuildVirtualCubeListener(CubeFacesList cfl) {
18
19 this.cfl = cfl;
20 }
21
22 // Instance method:
23 public void actionPerformed(ActionEvent e) {
24
25 CubeFace[] mainCubeFacesArray = cfl.getAllMainCubeFaces();
26 if (mainCubeFacesArray != null && mainCubeFacesDifferFromNull(mainCubeFacesArray)) {
27 try {
28 CubeConfiguration.buildVirtualCube(mainCubeFacesArray);
29 } catch (FaceletColorNoneException fcne) {
30 System.err.println(fcne);
31 } catch (NonExistingCubeletException nece) {
32 System.err.println(nece);
33 } catch (CubeletAlreadyAssignedException caae) {
34 System.err.println(caae);
35 }
36 }
37 }
38
39 // Static method:
40 public static boolean mainCubeFacesDifferFromNull(CubeFace[] hv) {
41 boolean notNull = true;
42 int index = 0;
43
44 while (notNull && index < hv.length) {
45
46 if (hv[index] == null) {
47 notNull = false;
48 }
49 index++;
50 }
51 return notNull;
52 }
53 }

Pagina 59 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CUBE_DeleteCubeFaceListener

1
1 package listeners.cube;
2
3 import java.awt.event.*;
4
5 import exceptions.NumberNotFoundException;
6 import model.CubeFacesList;
7 import view.ViewTabPanel2Cub;
8
9 public class B_CUBE_DeleteCubeFaceListener implements ActionListener {
10
11 private ViewTabPanel2Cub vtpc;
12 private CubeFacesList cfl;
13
14 // Constructor:
15 public B_CUBE_DeleteCubeFaceListener(ViewTabPanel2Cub vtpc, CubeFacesList cfl) {
16 this.vtpc = vtpc;
17 this.cfl = cfl;
18 }
19
20 // Instance method:
21 public void actionPerformed(ActionEvent e) {
22 if (cfl.getSize() != 0) {
23
24 try {
25 int cfID = vtpc.getCurrentCubeFace().getID();
26
27 // Before deleting, the view is set to the previous CubeFace:
28 int indexInArrayList = -1;
29 try {
30 indexInArrayList = cfl.searchIndexOfCubeFaceOnID(cfID);
31 } catch (NumberNotFoundException exp) {
32 }
33
34 if (indexInArrayList != -1 && indexInArrayList > 0) {
35 this.vtpc.setCurrentCubeFace(cfl.getCubeFace(indexInArrayList - 1));
36 } else {
37 vtpc.setCurrentCubeFace(null);
38 }
39
40 cfl.deleteCubeFace(cfID);
41
42 System.out.println("CubeFace \"" + cfID + "\" was deleted properly.");
43 } catch (NumberNotFoundException nnfe) {
44 System.err.println(nnfe);
45 }
46 }
47 }

Pagina 60 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CUBE_NextCubeFaceListener

1 package listeners.cube;
2
3 import java.awt.event.*;
4
5 import exceptions.NumberNotFoundException;
6 import model.CubeFace;
7 import model.CubeFacesList;
8 import view.ViewTabPanel2Cub;
9
10 public class B_CUBE_NextCubeFaceListener implements ActionListener {
11
12 private ViewTabPanel2Cub vtpc;
13 private CubeFacesList cfl;
14
15 // Constructor:
16 public B_CUBE_NextCubeFaceListener(ViewTabPanel2Cub vtpc, CubeFacesList cfl) {
17 this.vtpc = vtpc;
18 this.cfl = cfl;
19 }
20
21 // Instance method:
22 public void actionPerformed(ActionEvent e) {
23 CubeFace cf = vtpc.getCurrentCubeFace();
24 int indexInArrayList = -1;
25
26 if (cf != null) {
27 try {
28 indexInArrayList = cfl.searchIndexOfCubeFaceOnID(cf.getID());
29 } catch (NumberNotFoundException exp) {
30 /* System.err.println(exp); */}
31
32 if (indexInArrayList != -1 && indexInArrayList < (cfl.getSize() - 1)) {
33 vtpc.setCurrentCubeFace(cfl.getCubeFace(indexInArrayList + 1));
34 }
35 } else {
36 if (cfl.getSize() > 0) {
37 vtpc.setCurrentCubeFace(cfl.getCubeFace(0));
38 }
39 }
40 }
41 }

Pagina 61 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CUBE_PreviousCubeFaceListener

1 package listeners.cube;
2
3 import java.awt.event.*;
4
5 import view.ViewTabPanel2Cub;
6 import model.CubeFace;
7 import model.CubeFacesList;
8 import exceptions.NumberNotFoundException;
9
10 public class B_CUBE_PreviousCubeFaceListener implements ActionListener {
11
12 private ViewTabPanel2Cub vtpc;
13 private CubeFacesList cfl;
14
15 // Constructor:
16 public B_CUBE_PreviousCubeFaceListener(ViewTabPanel2Cub vtpc, CubeFacesList cfl) {
17 this.vtpc = vtpc;
18 this.cfl = cfl;
19 }
20
21 // Instance method:
22 public void actionPerformed(ActionEvent e) {
23
24 CubeFace cf = vtpc.getCurrentCubeFace();
25 int indexInArrayList = -1;
26 if (cf != null) {
27 try {
28 indexInArrayList = cfl.searchIndexOfCubeFaceOnID(cf.getID());
29 } catch (NumberNotFoundException exp) {
30 /* System.err.println(exp); */}
31
32 if (indexInArrayList != -1 && indexInArrayList > 0) {
33 vtpc.setCurrentCubeFace(cfl.getCubeFace(indexInArrayList - 1));
34 }
35 } else {
36 if (cfl.getSize() > 0) {
37 vtpc.setCurrentCubeFace(cfl.getCubeFace(0));
38 }
39 }
40 }
41 }

Pagina 62 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CUBE_TurnCFace90Degrees

1 package listeners.cube;
2
3 import java.awt.event.*;
4
5 import model.CubeFace;
6 import view.ViewTabPanel2Cub;
7
8 public class B_CUBE_TurnCFace90Degrees implements ActionListener {
9
10 private ViewTabPanel2Cub vtpc;
11 private boolean clockwise;
12
13 // Constructor:
14 public B_CUBE_TurnCFace90Degrees(ViewTabPanel2Cub vtpc, boolean clockwise) {
15
16 this.vtpc = vtpc;
17 this.clockwise = clockwise;
18 }
19
20 // Instance method:
21 public void actionPerformed(ActionEvent e) {
22
23 CubeFace cf = vtpc.getCurrentCubeFace();
24 if (cf != null) {
25
26 vtpc.getCurrentCubeFace().rotateCubeFace(clockwise);
27 }
28 }
29 }

Pagina 63 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_CUBE_TurnCFace90Degrees

1 package listeners.cube;
2
3 import java.awt.event.*;
4
5 import model.*;
6
7 public class Co_CUBE_ColorsOnCubeFaceDropdownListener implements ItemListener {
8
9 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
10 private int row;
11 private int column;
12 private CubeFace cf;
13 private boolean active;
14 // Prevent the listeners from getting triggerd,
15 // when the change is applied automatically.
16
17 // Constructor:
18 public Co_CUBE_ColorsOnCubeFaceDropdownListener(CubeFace cf, int row, int column) {
19 this.cf = cf;
20 this.row = row;
21 this.column = column;
22 this.active = true;
23 }
24
25 // Instance methods:
26 public void setActive(boolean active) {
27 this.active = active;
28 }
29
30 public void itemStateChanged(ItemEvent e) {
31
32 /*
33 * e.getStateChange() equals '2' on deselecting and 1 when selecting. '1' is
34 * represented by ItemEvent.SELECTED. Enabling using "active" was needed
35 * during an update of the respective VisualCubeFace.
36 */
37 if (e.getStateChange() == ItemEvent.SELECTED && active) {
38
39 int colorIntValue = cbthsl.translateColorsStringToInt((String) e.getItem());
40 double confidenceDoubleValue = 100.0;
41
42 /*
43 * The idea is: When the user manually adapts a facelet, the certainty of
44 * that facelet is 100% from then on. If the user would make it "None",
45 * then there's 0% certainty.
46 */
47 if (colorIntValue == 6) {
48 confidenceDoubleValue = 0.0;
49 }
50 cf.setOneColorOneConfidenceLevel(colorIntValue, confidenceDoubleValue, row, column);
51 }
52 }
53 }

Pagina 64 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_IMG_BrowseImageListener

1 package listeners.img;
2
3 import java.awt.event.*;
4 import java.io.*;
5
6 import cbthFileChooser.CBTHFileChooser;
7 import model.CBTHImage;
8 import model.CBTHImagesList;
9
10 public class B_IMG_BrowseImageListener implements ActionListener {
11
12 private CBTHFileChooser cbthfc;
13 private CBTHImagesList imgl;
14 private CBTHImage img;
15
16 // Constructor:
17 public B_IMG_BrowseImageListener(CBTHFileChooser cbthfc, CBTHImagesList imgl) {
18 this.cbthfc = cbthfc;
19 this.imgl = imgl;
20 }
21
22 // Instance method:
23 public void actionPerformed(ActionEvent e) {
24 File f = cbthfc.fcOpenFile(0);
25 if (f != null) {
26 img = new CBTHImage(null, f, -1, -1, -1, -1);
27 imgl.addCBTHImage(img);
28 }
29 }
30 }

Pagina 65 van 329 CubeThesis™ Depamelaere-Deschuytter


class Co_CUBE_MainCFacesDropdownListener

1 package listeners.cube;
2
3 import java.awt.event.*;
4
5 import model.CubeFace;
6 import view.ViewTabPanel2Cub;
7
8 public class Co_CUBE_MainCFacesDropdownListener implements ItemListener {
9
10 private ViewTabPanel2Cub vtpc;
11
12 // Constructor:
13 public Co_CUBE_MainCFacesDropdownListener(ViewTabPanel2Cub vtpc) {
14 this.vtpc = vtpc;
15 }
16
17 // Instance method:
18 public void itemStateChanged(ItemEvent e) {
19
20 CubeFace cf = null;
21 /*
22 * e.getStateChange() equals '2' on deselecting and 1 when selecting. '1' is
23 * represented by ItemEvent.SELECTED. If another CubeFace is selected from
24 * the dropdown, this method is invoked twice on different objects.
25 */
26 if (e.getStateChange() == ItemEvent.SELECTED) {
27 cf = (CubeFace) e.getItem();
28 vtpc.cubeFacePanelUpUpdate(cf);
29 }
30 }
31 }

Pagina 66 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_IMG_BrowseImageListener , B_IMG_ColorCalibrationListener

1 package listeners.img;
2
3 import java.awt.event.*;
4 import java.io.*;
5
6 import cbthFileChooser.CBTHFileChooser;
7 import model.CBTHImage;
8 import model.CBTHImagesList;
9
10 public class B_IMG_BrowseImageListener implements ActionListener {
11
12 private CBTHFileChooser cbthfc;
13 private CBTHImagesList imgl;
14 private CBTHImage img;
15
16 // Constructor:
17 public B_IMG_BrowseImageListener(CBTHFileChooser cbthfc, CBTHImagesList imgl) {
18 this.cbthfc = cbthfc;
19 this.imgl = imgl;
20 }
21
22 // Instance method:
23 public void actionPerformed(ActionEvent e) {
24 File f = cbthfc.fcOpenFile(0);
25 if (f != null) {
26 img = new CBTHImage(null, f, -1, -1, -1, -1);
27 imgl.addCBTHImage(img);
28 }
29 }
30 }

1 package listeners.img;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5
6 import exceptions.WorkInProgressException;
7
8 public class B_IMG_ColorCalibrationListener implements ActionListener {
9
10 // Constructor:
11 public B_IMG_ColorCalibrationListener() {
12 super();
13 }
14
15 // Instance method:
16 public void actionPerformed(ActionEvent e) {
17 try {
18 throw new WorkInProgressException("The button: \"Color calibration\" ");
19 } catch (WorkInProgressException wipe) {
20 System.out.println(wipe);
21 }
22 }
23 }

Pagina 67 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_IMG_ColorEstimationListener

1 package listeners.img;
2
3 import java.awt.event.*;
4 import javax.swing.*;
5
6 import exceptions.NoImageForColorEstimationException;
7 import model.*;
8 import view.ViewTabPanel1Img;
9
10 public class B_IMG_ColorEstimationListener implements ActionListener {
11
12 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
13 private ViewTabPanel1Img vtpi;
14 private CubeFacesList cfl;
15
16 // Constructor:
17 public B_IMG_ColorEstimationListener(ViewTabPanel1Img vtpi, CubeFacesList cfl) {
18
19 this.vtpi = vtpi;
20 this.cfl = cfl;
21 }
22
23 // Instance method:
24 public void actionPerformed(ActionEvent e) {
25
26 try {
27 // Launch color-estimation upon the actual CBTHImage:
28 CBTHImage temporyImage = vtpi.getImgTemporary();
29
30 if (temporyImage == null) {
31 throw new NoImageForColorEstimationException();
32 }
33
34 else {
35 CubeFace cf = ColorEstimation.colorRecognition(temporyImage);
36 cfl.addCubeFace(cf);
37
38 JPanel content = cf.createVCubeFace();
39
40 /*
41 * Spawn obtained CubeFace from the color-recognition. In automatic
42 * routine, this is omitted.
43 */
44 JFrame f = cbthsl.createCubeThesisFrame("Result color-estimation...");
45 f.add(content);
46 f.pack();
47 f.setVisible(true);
48 }
49 } catch (NoImageForColorEstimationException nifcee) {
50 System.err.println(nifcee);
51 }
52 }
53 }

Pagina 68 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_IMG_DeleteImageListener , B_IMG_SaveImagesListener

1 package listeners.img;
2
3 import java.awt.event.*;
4
5 import exceptions.NumberNotFoundException;
6 import model.CBTHImage;
7 import model.CBTHImagesList;
8 import view.ViewTabPanel1Img;
9
10 public class B_IMG_DeleteImageListener implements ActionListener {
11
12 private ViewTabPanel1Img vtpi;
13 private CBTHImagesList imgl;
14 private CBTHImage imgToDelete;
15
16 // Constructor:
17 public B_IMG_DeleteImageListener(ViewTabPanel1Img vtpi, CBTHImagesList imgl) {
18 this.vtpi = vtpi;
19 this.imgl = imgl;
20 }
21
22 // Instance method:
23 public void actionPerformed(ActionEvent e) {
24 if (imgl.getSize() != 0) {
25
26 try {
27 imgToDelete = vtpi.getImgCombo();
28 String imgToString = imgToDelete.toString();
29 imgl.deleteCBTHImage(imgToDelete.getID());
30 vtpi.updateImgCropSpinners(null);
31
32 System.out.println("Image \"" + imgToString + "\" was deleted properly.");
33 } catch (NumberNotFoundException nnfe) {
34 System.err.println(nnfe);
35 }
36 }
37 }
38 }

1 package listeners.img;
2
3 import java.awt.event.*;
4
5 import cbthFileChooser.FileIO;
6
7 public class B_IMG_SaveImagesListener implements ActionListener {
8
9 // Constructor:
10 public B_IMG_SaveImagesListener() {
11 super();
12 }
13
14 // Instance method:
15 public void actionPerformed(ActionEvent e) {
16
17 // Saves only the "physical" images, not the paths of references in
18 // the SaveFile.cbth:
19 FileIO.savePhysicalImages();
20 }
21 }

Pagina 69 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_IMG_UpdateCropParamListener

1 package listeners.img;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import javax.swing.SpinnerNumberModel;
6
7 import model.CBTHSettingsList;
8 import model.CommonObjects;
9 import view.ViewTabPanel1Img;
10
11 public class B_IMG_UpdateCropParamListener implements ActionListener {
12
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14 private ViewTabPanel1Img vtpi;
15
16 // Constructor:
17 public B_IMG_UpdateCropParamListener(ViewTabPanel1Img vtpi) {
18 this.vtpi = vtpi;
19 }
20
21 // Instance method:
22 /**
23 * This method will update the respective CBTHSettings from the manual
24 * crop-parameters.
25 */
26 public void actionPerformed(ActionEvent e) {
27 cbthsl.setInt("xCoCrop",
28 (((SpinnerNumberModel) vtpi.getS_IMG_X_CO().getModel()).getNumber().intValue()));
29 cbthsl.setInt("yCoCrop",
30 (((SpinnerNumberModel) vtpi.getS_IMG_Y_CO().getModel()).getNumber().intValue()));
31 cbthsl.setInt("widthCrop",
32 (((SpinnerNumberModel) vtpi.getS_IMG_Width().getModel()).getNumber().intValue()));
33 cbthsl.setInt("heigthCrop", (((SpinnerNumberModel) vtpi.getS_IMG_Height().getModel())
34 .getNumber().intValue()));
35 System.out.println("Crop-parameters have been updated.");
36 }
37 }

Pagina 70 van 329 CubeThesis™ Depamelaere-Deschuytter


class Co_IMG_CBTHImagesListDropdownListener

1 package listeners.img;
2
3 import java.awt.event.*;
4
5 import model.CBTHImage;
6 import view.ViewTabPanel1Img;
7
8 public class Co_IMG_CBTHImagesListDropdownListener implements ItemListener {
9
10 private ViewTabPanel1Img vtpi;
11
12 // Constructor:
13 public Co_IMG_CBTHImagesListDropdownListener(ViewTabPanel1Img vtpi) {
14 this.vtpi = vtpi;
15 }
16
17 // Instance method:
18 public void itemStateChanged(ItemEvent e) {
19 CBTHImage imgSelected = null;
20 imgSelected = (CBTHImage) e.getItem();
21
22 /*
23 * e.getStateChange() equals '2' on deselecting and 1 when selecting. '1' is
24 * represented by ItemEvent.SELECTED. If another CBTHImage is selected from
25 * the dropdown, this method is invoked twice on different objects.
26 */
27 if ((e.getStateChange() == ItemEvent.SELECTED && imgSelected != null)) {
28
29 vtpi.updateImgCropSpinners(imgSelected);
30 vtpi.updateImgWindow(imgSelected);
31 // System.out.println("Windowupdate: CBTHImage \""+
32 // imgSelected.toString()+"\" and its spinners are loaded.");
33 } else {
34 vtpi.updateImgWindow(null);
35 }
36 }
37 }

Pagina 71 van 329 CubeThesis™ Depamelaere-Deschuytter


class S_IMG_CropSpinnersListener

1 package listeners.img;
2
3 import javax.swing.*;
4 import javax.swing.event.*;
5
6 import model.CBTHImage;
7 import view.ViewTabPanel1Img;
8
9 /**
10 * DISCLAIMER: This class is implementing functionality to react on the changes
11 * of the CBTHImage-spinners. It does the job, but there're probably better ways
12 * to cope with this.
13 */
14 public class S_IMG_CropSpinnersListener implements ChangeListener {
15
16 private ViewTabPanel1Img vtpi;
17 private CBTHImage currentImg;
18
19 private JSpinner s_IMG_X_CO;
20 private JSpinner s_IMG_Y_CO;
21 private JSpinner s_IMG_Width;
22 private JSpinner s_IMG_Height;
23
24 private int a;
25 private int b;
26 private int c;
27 private int d;
28
29 // Constructors:
30 public S_IMG_CropSpinnersListener(ViewTabPanel1Img vtpi) {
31
32 this.currentImg = null;
33 this.vtpi = vtpi;
34
35 this.s_IMG_X_CO = null;
36 this.s_IMG_Y_CO = null;
37 this.s_IMG_Width = null;
38 this.s_IMG_Height = null;
39
40 this.a = 0;
41 this.b = 0;
42 this.c = 0;
43 this.d = 0;
44 }
45
46 public S_IMG_CropSpinnersListener(ViewTabPanel1Img vtpa, CBTHImage afb,
47 JSpinner s_IMG_X_CO, JSpinner s_IMG_Y_CO, JSpinner s_IMG_Width,
48 JSpinner s_IMG_Height) {
49
50 this.currentImg = afb;
51 this.vtpi = vtpa;
52
53 this.s_IMG_X_CO = s_IMG_X_CO;
54 this.s_IMG_Y_CO = s_IMG_Y_CO;
55 this.s_IMG_Width = s_IMG_Width;
56 this.s_IMG_Height = s_IMG_Height;
57
58 this.a = 0;
59 this.b = 0;
60 this.c = 0;
61 this.d = 0;
62 }
63
64 // Instance method:
65 /**
66 * To avoid illegal coordinates when cropping an image, the upperlimit of the

Pagina 72 van 329 CubeThesis™ Depamelaere-Deschuytter


class S_IMG_CropSpinnersListener

67 * width and height have to be restricted and updated when moving x-co and
68 * y-xo.
69 */
70 public void stateChanged(ChangeEvent e) {
71
72 /*
73 * In former version each time this.spinners private attributes where
74 * refreshed
75 */
76
77 currentImg = vtpi.getImgTemporary();
78
79 if (currentImg != null) {
80 a = ((SpinnerNumberModel) s_IMG_X_CO.getModel()).getNumber().intValue();
81 b = ((SpinnerNumberModel) s_IMG_Y_CO.getModel()).getNumber().intValue();
82 c = ((SpinnerNumberModel) s_IMG_Width.getModel()).getNumber().intValue();
83 d = ((SpinnerNumberModel) s_IMG_Height.getModel()).getNumber().intValue();
84
85 if ((a + c) > currentImg.getWidthOriginal()) {
86 c = currentImg.getWidthOriginal() - a;
87 s_IMG_Width.setModel(new SpinnerNumberModel(c, 0, c, 1));
88 } else {
89 if (((SpinnerNumberModel) s_IMG_Width.getModel()).getMaximum()
90 .compareTo((currentImg.getWidthOriginal() - a)) < 0) {
91 s_IMG_Width.setModel(
92 new SpinnerNumberModel(c, 0, currentImg.getWidthOriginal() - a, 1));
93 }
94 }
95
96 if ((b + d) > currentImg.getHeightOriginal()) {
97 d = currentImg.getHeightOriginal() - b;
98 s_IMG_Height.setModel(new SpinnerNumberModel(d, 0, d, 1));
99 } else {
100 if (((SpinnerNumberModel) s_IMG_Height.getModel()).getMaximum()
101 .compareTo((currentImg.getHeightOriginal() - b)) < 0) {
102 s_IMG_Height.setModel(
103 new SpinnerNumberModel(d, 0, currentImg.getHeightOriginal() - b, 1));
104 }
105 }
106 currentImg.setNewCropped(a, b, c, d);
107 }
108 vtpi.updateImgWindow(currentImg);
109 }
110 }

Pagina 73 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemAboutListener

1 package listeners.menu;
2
3 import java.awt.event.*;
4 import javax.swing.*;
5
6 import model.CBTHSettingsList;
7 import model.CommonObjects;
8
9 public class MenuItemAboutListener implements ActionListener {
10
11 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
12
13 // Constructor:
14 public MenuItemAboutListener() {
15 super();
16 }
17
18 // Instance method:
19 public void actionPerformed(ActionEvent e) {
20
21 String[] iconPathComp = { "img", "icon", "RubiksCube220x210.png" };
22 String iconPath = cbthsl.makeSysIndepFilePath(iconPathComp, 2);
23 ImageIcon rubiksCubeLogo = new ImageIcon(iconPath);
24 String newLine = cbthsl.getString("newLine");
25 JOptionPane.showMessageDialog(null,
26 "© CubeThesis as a Java program was developed to generate a series " + newLine
27 + "of solving commands for the Rubik's Cube based on "
28 + "visual input from some webcam." + newLine
29 + "It was developed as part of the Masters' Thesis of "
30 + "Simon Deschuytter and Pieter Depamelaere." + newLine
31 + "Promotors: K. Bruggeman & R. Claeys" + newLine + newLine
32 + "CubeThesis uses:" + newLine
33 + "- an OpenCV-Library to retrieve streams from the cameradevices." + newLine
34 + "- the Kociemba-algorithm via the \"Cubie\" Java-software, "
35 + "which Jaap Scherphuis provided." + newLine
36 + "- a Standalone Blender Game to visualize the virtual Cube." + newLine
37 + "- generated Javadoc files to show in some webbrowser, "
38 + "that yield for basic internal structure." + newLine + newLine + newLine
39 + "Encountering problems about CubeThesis? Please contact:" + newLine
40 + "pieter.depamelaere@hotmail.com",
41 "About © CubeThesis...", JOptionPane.INFORMATION_MESSAGE, rubiksCubeLogo);
42 }
43 }

Pagina 74 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemConsoleClearListener

1 package listeners.menu;
2
3 import java.awt.event.*;
4
5 import console.ViewConsolePanel;
6
7 public class MenuItemConsoleClearListener implements ActionListener {
8
9 private ViewConsolePanel p_vcp;
10
11 // Constructor:
12 public MenuItemConsoleClearListener(ViewConsolePanel p_vcp) {
13
14 this.p_vcp = p_vcp;
15 }
16
17 // Instance method:
18 public void actionPerformed(ActionEvent e) {
19
20 this.p_vcp.updateLogFilesByFlushConsole(false, false);
21 }
22 }

Pagina 75 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemCustomizeSettingsListener

1 package listeners.menu;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import java.awt.event.KeyEvent;
6 import javax.swing.*;
7
8 import listeners.cbthsettings.MenuItemSortListener;
9 import model.CommonObjects;
10 import model.CBTHSettingsList;
11 import view.VisualCBTHSettingsCustomizer;
12
13 public class MenuItemCustomizeSettingsListener implements ActionListener {
14
15 private CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
16 private JMenuBar menuBar;
17 private JMenu menu_Sort;
18 private JMenuItem menuItem_SortById;
19 private JMenuItem menuItem_SortByLabelText;
20 private JMenuItem menuItem_SortByType;
21
22 // Constructor:
23 public MenuItemCustomizeSettingsListener() {
24 this.menuBar = new JMenuBar();
25
26 this.menu_Sort = new JMenu("Sort");
27 menu_Sort.setMnemonic(KeyEvent.VK_S);
28
29 menuItem_SortById = new JMenuItem("Sort by iD (logical order)");
30 menuItem_SortById.setMnemonic(KeyEvent.VK_I);
31 menuItem_SortById.addActionListener(new MenuItemSortListener(0));
32
33 menuItem_SortByLabelText = new JMenuItem("Sort by labeltext (alphabetic)");
34 menuItem_SortByLabelText.setMnemonic(KeyEvent.VK_L);
35 menuItem_SortByLabelText.addActionListener(new MenuItemSortListener(1));
36
37 menuItem_SortByType = new JMenuItem("Sort by type (alphabetic)");
38 menuItem_SortByType.setMnemonic(KeyEvent.VK_T);
39 menuItem_SortByType.addActionListener(new MenuItemSortListener(2));
40
41 menu_Sort.add(menuItem_SortById);
42 menu_Sort.add(menuItem_SortByLabelText);
43 menu_Sort.add(menuItem_SortByType);
44
45 menuBar.add(menu_Sort);
46 }
47
48 // Instance method:
49 public void actionPerformed(ActionEvent e) {
50 JFrame f_customCBTHSettings = cbthsl
51 .createCubeThesisFrame("Customize CBTHSettings...");
52 VisualCBTHSettingsCustomizer vcbthsc = new VisualCBTHSettingsCustomizer();
53 cbthsl.addObserver(vcbthsc);
54 f_customCBTHSettings.add(vcbthsc);
55 f_customCBTHSettings.setJMenuBar(menuBar);
56 f_customCBTHSettings.pack();
57 f_customCBTHSettings.setVisible(true);
58 }
59 }

Pagina 76 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemExitListener

1 package listeners.menu;
2
3 import java.awt.event.*;
4
5 import cbthFileChooser.FileIO;
6 import connection.conWithRobot.CommunicationRobotThread;
7 import console.ViewConsolePanel;
8 import listeners.cam.T_CAM_LiveStreamItemListener;
9 import model.CBTHSettingsList;
10 import model.CommonObjects;
11
12 public class MenuItemExitListener implements ActionListener {
13
14 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
15 private ViewConsolePanel p_vcp;
16
17 // Constructor:
18 public MenuItemExitListener(ViewConsolePanel p_vcp) {
19
20 this.p_vcp = p_vcp;
21 }
22
23 // Instance method:
24 public void actionPerformed(ActionEvent e) {
25
26 FileIO.saveProject();
27
28 // Close connections: camerastream and communication with the robot:
29 CommunicationRobotThread comRobot = CommonObjects.getCommunicatieRobot();
30 T_CAM_LiveStreamItemListener lsil = CommonObjects.getCamLSIL();
31
32 if (comRobot.getLinkRobotEstablished()) {
33 comRobot.stopCommunicationRobot();
34 }
35
36 // If the stream is not properly closed, a "hs_err_pidxxx.log"-file
37 // is created.
38 if (lsil.getLinkCamEstablished()) {
39 lsil.disconnectFromCapDevice();
40 }
41
42 if (cbthsl.getBoolean("saveCBTHSettingsOnExit")) {
43 // If true, CBTHSettings are exported at this point.
44 cbthsl.exportCBTHSettingsToTXT();
45 }
46
47 // Flush the whole console and add footers to the logFiles:
48 this.p_vcp.updateLogFilesByFlushConsole(false, true);
49
50 System.exit(0);
51 }
52 }

Pagina 77 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemExportSettingsToText , MenuItemImportSettingsFromText

1 package listeners.menu;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5
6 import model.CommonObjects;
7 import model.CBTHSettingsList;
8
9 public class MenuItemExportSettingsToText implements ActionListener {
10
11 private CBTHSettingsList cbthsl;
12
13 // Constructor:
14 public MenuItemExportSettingsToText() {
15 cbthsl = CommonObjects.getCBTHSettingsList();
16 }
17
18 // Instance method:
19 public void actionPerformed(ActionEvent e) {
20 cbthsl.exportCBTHSettingsToTXT();
21 }
22 }

1 package listeners.menu;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5
6 import model.CBTHSettingsList;
7 import model.CommonObjects;
8
9 public class MenuItemImportSettingsFromText implements ActionListener {
10
11 private CBTHSettingsList cbthsl;
12
13 // Constructor:
14 public MenuItemImportSettingsFromText() {
15 cbthsl = CommonObjects.getCBTHSettingsList();
16 }
17
18 // Instance method:
19 public void actionPerformed(ActionEvent e) {
20 cbthsl.importCBTHSettingsFromTXT();
21 }
22 }

Pagina 78 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemJavaDocListener

1 package listeners.menu;
2
3 import java.awt.Desktop;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.io.File;
7 import java.net.*;
8
9 import model.CBTHSettingsList;
10 import model.CommonObjects;
11
12 public class MenuItemJavaDocListener implements ActionListener {
13
14 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
15
16 // Constructor:
17 public MenuItemJavaDocListener() {
18 super();
19 }
20
21 // Instance method:
22 public void actionPerformed(ActionEvent e) {
23
24 String[] pathStructure = { "doc", "overview-summary.html" };
25 String url = cbthsl.makeSysIndepFilePath(pathStructure, 2);
26
27 // Source:
28 // http://stackoverflow.com/questions/10967451/
29 // open-a-link-in-browser-with-java-button viewed on 21/03/2016
30 // Source:
31 // http://stackoverflow.com/questions/6098472/
32 // pass-a-local-file-in-to-url-in-java viewed on 21/03/2016
33
34 Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
35 if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
36 try {
37 URI uri = new File(url).toURI();
38 desktop.browse(uri);
39 } catch (Exception exc) {
40 System.err.println("ERROR: Some unexpected error occurred during "
41 + "opening the JavaDoc. Our apologies for the inconvenience.");
42 exc.printStackTrace();
43 }
44 }
45 }
46 }

Pagina 79 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemListCommandsListener

1 package listeners.menu;
2
3 import java.awt.Dimension;
4 import java.awt.event.*;
5 import java.awt.GridLayout;
6 import javax.swing.*;
7 import javax.swing.table.TableColumn;
8
9 import console.ConsoleCommands;
10 import console.ViewConsolePanel;
11 import model.CBTHSettingsList;
12 import model.CommonObjects;
13
14 public class MenuItemListCommandsListener implements ActionListener {
15
16 private static CBTHSettingsList cbthsl = null;
17 private JTable table = null;
18 private ViewConsolePanel vcp = null;
19 private String[] columnNames = { "Console-command", "Description" };
20 private String[][] data = null;
21
22 // Constructor:
23 public MenuItemListCommandsListener(ViewConsolePanel p_vcp) {
24
25 cbthsl = CommonObjects.getCBTHSettingsList();
26 this.vcp = p_vcp;
27 data = ConsoleCommands.getSupCommands();
28 table = new JTable(data, columnNames);
29
30 TableColumn column = null;
31 for (int i = 0; i < columnNames.length; i++) {
32 column = table.getColumnModel().getColumn(i);
33 switch (i) {
34 case 0:
35 column.setPreferredWidth(100);
36 break;
37 case 1:
38 column.setPreferredWidth(450);
39 break;
40 default:
41 column.setPreferredWidth(200);
42 break;
43 }
44 }
45
46 table.addMouseListener(new MouseAdapter() {
47 public void mouseClicked(MouseEvent e) {
48 selectedCommandToPrompt();
49 }
50 });
51 }
52
53 // Instance method:
54 public void actionPerformed(ActionEvent e) {
55
56 table.setPreferredScrollableViewportSize(new Dimension(550, 200));
57 table.setFillsViewportHeight(true);
58
59 // Create the scroll pane/JPanel/JFrame and add the table to it.
60 JScrollPane sp_tableScroll = new JScrollPane(table);
61 JPanel p_tablepanel = new JPanel(new GridLayout(1, 0));
62 JFrame frame = cbthsl.createCubeThesisFrame("Supported console-commands");
63 // Add the scroll pane to this panel.
64 p_tablepanel.add(sp_tableScroll);
65 frame.add(p_tablepanel);
66 frame.pack();

Pagina 80 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemListCommandsListener

67 frame.setVisible(true);
68 }
69
70 public void selectedCommandToPrompt() {
71 vcp.setTextCommandPrompt(data[table.getSelectedRow()][0]);
72 }
73 }

Pagina 81 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemNewProjectListener

1 package listeners.menu;
2
3 import java.awt.event.*;
4 import java.io.*;
5
6 import javax.swing.JOptionPane;
7
8 import console.ViewConsolePanel;
9 import model.*;
10
11 public class MenuItemNewProjectListener implements ActionListener {
12
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14 private static String newLine = cbthsl.getString("newLine");
15 private static String fS = cbthsl.getString("fileSeparator");
16 private CBTHImagesList imgl;
17 private CubeFacesList cfl;
18 private ViewConsolePanel p_vcp;
19
20 // Constructor:
21 public MenuItemNewProjectListener(CBTHImagesList imgl, CubeFacesList cfl,
22 ViewConsolePanel p_vcp) {
23
24 this.imgl = imgl;
25 this.cfl = cfl;
26 this.p_vcp = p_vcp;
27 }
28
29 // Instance method:
30 public void actionPerformed(ActionEvent e) {
31
32 String newProjectName = (String) JOptionPane.showInputDialog(null,
33 "Enter a name for this new project. (Avoid spaces in projectname)" + newLine
34 + "Your project will saved to the " + fS + "CubeThesisProjects - folder."
35 + newLine + "The project could also be saved to some subfolder by adding "
36 + "this OS-specific fileseparator: \"" + fS + "\"",
37 "Creation of new project...", JOptionPane.QUESTION_MESSAGE, null, null,
38 "NieuwProject");
39
40 if (newProjectName != null) {
41 String[] pathStruct1 = { "CubeThesisProjects", newProjectName, "ImgOriginal" };
42 String[] pathStruct2 = { "CubeThesisProjects", newProjectName, "ImgCropped" };
43
44 File org = new File(cbthsl.makeSysIndepFilePath(pathStruct1, 2));
45 File cropped = new File(cbthsl.makeSysIndepFilePath(pathStruct2, 2));
46
47 org.mkdirs();
48 cropped.mkdirs();
49
50 imgl.deleteAllCBTHImages();
51 cfl.deleteAllCubeFaces();
52 cfl.resetMainCubeFaces();
53 CubeConfiguration.setStartCubeletPerm(null);
54 CubeConfiguration.setStartCubeletOri(null);
55 CubeConfiguration.setStartFaceOri(null);
56 CubeConfiguration.setColorMapKey(null);
57 CommandSeq.stopAsQuicklyAsPossile();
58 CommandSeq.setSolutionCommandsMatrix(null, null, 0);
59
60 cbthsl.setCurrentProject(org.getParentFile());
61 p_vcp.updateLogFilesByFlushConsole(true, false);
62
63 System.out.println("Project \"" + newProjectName + "\" was created succesfully.");
64 }
65 }
66 }

Pagina 82 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemOpenProjectListener

1 package listeners.menu;
2
3 import java.awt.event.*;
4 import java.io.*;
5
6 import cbthFileChooser.CBTHFileChooser;
7 import cbthFileChooser.FileIO;
8 import console.ViewConsolePanel;
9 import model.CBTHSettingsList;
10 import model.CommonObjects;
11
12 public class MenuItemOpenProjectListener implements ActionListener {
13
14 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
15 private CBTHFileChooser cbthfc;
16 private ViewConsolePanel p_vcp;
17
18 // Constructor:
19 public MenuItemOpenProjectListener(CBTHFileChooser cbthfc, ViewConsolePanel p_vcp) {
20
21 this.cbthfc = cbthfc;
22 this.p_vcp = p_vcp;
23 }
24
25 // Instance method:
26 public void actionPerformed(ActionEvent e) {
27
28 // Launch pop-up window to let user choose:
29 File f = cbthfc.fcOpenFile(1);
30
31 if (f != null) {
32
33 cbthsl.setCurrentProject(new File(f.getParent()));
34 p_vcp.updateLogFilesByFlushConsole(true, false);
35 FileIO.openProject(f);
36 }
37 }
38 }

Pagina 83 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemRestoreFactorySettings , MenuItemSaveAsProjectListener

1 package listeners.menu;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5
6 import model.CBTHSettingsList;
7 import model.CommonObjects;
8
9 public class MenuItemRestoreFactorySettings implements ActionListener {
10
11 private CBTHSettingsList cbthsl;
12
13 // Constructor:
14 public MenuItemRestoreFactorySettings() {
15 cbthsl = CommonObjects.getCBTHSettingsList();
16 }
17
18 // Instance method:
19 public void actionPerformed(ActionEvent e) {
20 cbthsl.restoreSituationSimonAndPieter();
21 }
22 }

1 package listeners.menu;
2
3 import java.awt.event.*;
4
5 import cbthFileChooser.CBTHFileChooser;
6
7 public class MenuItemSaveAsProjectListener implements ActionListener {
8
9 private CBTHFileChooser cbthfc;
10
11 // Constructor:
12 public MenuItemSaveAsProjectListener(CBTHFileChooser cbthfc) {
13
14 this.cbthfc = cbthfc;
15 }
16
17 // Instance method:
18 public void actionPerformed(ActionEvent e) {
19
20 cbthfc.fcSaveFile(1);
21 }
22 }

Pagina 84 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemSaveProjectListener

1 package listeners.menu;
2
3 import java.awt.event.*;
4
5 import cbthFileChooser.FileIO;
6
7 public class MenuItemSaveProjectListener implements ActionListener {
8
9 // Constructor:
10 public MenuItemSaveProjectListener() {
11 super();
12 }
13
14 // Instance method:
15 public void actionPerformed(ActionEvent e) {
16
17 FileIO.saveProject();
18 }
19 }

Pagina 85 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemUserManualListener

1 package listeners.menu;
2
3 import java.awt.event.*;
4
5 import javax.swing.*;
6
7 import model.CBTHSettingsList;
8 import model.CommonObjects;
9
10 public class MenuItemUserManualListener implements ActionListener {
11
12 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
13
14 // Constructor:
15 public MenuItemUserManualListener() {
16 super();
17 }
18
19 // Instance method:
20 public void actionPerformed(ActionEvent e) {
21
22 JFrame frame = cbthsl.createCubeThesisFrame("Concise user's manual");
23 String newLine = cbthsl.getString("newLine");
24 JTextArea ta_Manual = new JTextArea(15, 80);
25
26 ta_Manual.setLineWrap(false);
27 ta_Manual.setEditable(false);
28 ta_Manual.setFont(cbthsl.getFont("guiFont1"));
29 ta_Manual.setText("CUBETHESIS USER MANUAL" + newLine + "======================"
30 + newLine + "" + newLine + "CubeThesis' GUI mainly consists of three parts:"
31 + newLine + "- A menubar, on top of the window, where several general functions "
32 + "are to be found." + newLine
33 + "- A tabpane, located in the middle, with 5 tabs." + newLine
34 + "- A console, located on the bottom of the window." + newLine + "" + newLine
35 + "The menubar, provides menu's [FILE], [CONSOLE], [CBTH-SETTINGS] & " + "[HELP]."
36 + newLine + "" + newLine
37 + "From left to right the tabs are: [CAMERA], [IMAGE], [CUBE], "
38 + "[ALGORITHMIC SOLVER] & [AUTOMATIC MODE]." + newLine
39 + "These tabs allow to load a specific group of functions relevant for "
40 + "that item." + newLine
41 + "E.g.: On tab [IMAGE], the cropspinners are relevant buttons." + newLine + ""
42 + newLine + "Each tabpanel consists of a controlPanel on the left hand side & a "
43 + "windowPanel on the right hand side." + newLine
44 + "The leftpanel hosts the buttons and stuff, while the right panel "
45 + "yields for more information." + newLine
46 + "The idea is that the user chooses to work in manual/automatic mode:" + newLine
47 + "Manual mode: The user will loop manually through the first 4 "
48 + "panels from left to right." + newLine
49 + "Automatic mode: The user navigates to tab [AUTOMATIC MODE] &"
50 + " clicks \"Automatic routine\"." + newLine + "" + newLine
51 + "The console will keep record of the communication between CubeThesis "
52 + "and the user." + newLine
53 + "Feedback output as well as error-messages (\" > : \") are "
54 + "displayed in there to help the user." + newLine
55 + "Underneath the console, a bar was created by means of a commandprompt"
56 + newLine + "CubeThesis will react at some supported commands (these are listed "
57 + "in menu \"Commands...\")." + newLine
58 + "These commands and other input from the user is shown on the "
59 + "console preceded by (\" < : \")" + newLine
60 + "The text on the console in logged in two files, a general logfile "
61 + "& a project-logfile." + newLine + "" + newLine
62 + "For most common issues, the occurred error will be displayed in "
63 + "the console." + newLine
64 + "Rebooting the software, can be a general first hint." + newLine
65 + "The solution to some problems is elaborated in the Paper & Addendum "
66 + "of the" + newLine

Pagina 86 van 329 CubeThesis™ Depamelaere-Deschuytter


class MenuItemUserManualListener

67 + "Thesis: \"Oplossen Rubik's Kubus m.b.v. een deltarobot\" [Dutch], "


68 + "by Simon Deschuytter & Pieter Depamelaere.");
69
70 ta_Manual.setCaretPosition(0);
71 frame.add(new JScrollPane(ta_Manual));
72 frame.pack();
73 frame.setVisible(true);
74 }
75 }

Pagina 87 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_SOLV_BlenderGUIListener

1 package listeners.solv;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import java.io.File;
6 import java.io.IOException;
7
8 import model.CBTHSettingsList;
9 import model.CommonObjects;
10
11 public class B_SOLV_BlenderGUIListener implements ActionListener {
12
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14
15 // Constructor:
16 public B_SOLV_BlenderGUIListener() {
17 super();
18 }
19
20 // Instance method:
21 public void actionPerformed(ActionEvent e) {
22
23 System.out.println("WARNING: The BlenderGUI only works on windows-pc's.");
24 String[] pathStructure = { "ExtLib", "BlenderGUICBTH", "BlenderGUICBTH.exe" };
25 String blenderGUIPath = cbthsl.makeSysIndepFilePath(pathStructure, 2);
26
27 try {
28 Runtime.getRuntime().exec(blenderGUIPath, null,
29 new File(blenderGUIPath).getParentFile());
30 System.out.println(
31 "Within a few moments, the BlenderGUI will launch, " + "be patient...");
32 } catch (IOException e1) {
33 System.err.println(
34 "ERROR: An IOException occurred. Our apologies " + "for the inconvenience.");
35 System.err.println(
36 "ERROR: DISCLAIMER: The Blender-GUI is only " + "supported for Windows-pc's.");
37 e1.printStackTrace();
38 }
39 }
40 }

Pagina 88 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_SOLV_CubeToSolverListener

1 package listeners.solv;
2
3 import java.awt.event.*;
4
5 import exceptions.NotAvailableException;
6 import model.CubeConfiguration;
7 import solver.solverJS.viewSolverJS.Cubie;
8
9 public class B_SOLV_CubeToSolverListener implements ActionListener {
10
11 private Cubie cubie;
12
13 // Constructor:
14 public B_SOLV_CubeToSolverListener(Cubie cubie) {
15
16 this.cubie = cubie;
17 }
18
19 // Instance methods:
20 public void actionPerformed(ActionEvent e) {
21 try {
22 cubeToSolver();
23 } catch (NotAvailableException nae) {
24 System.err.println(nae);
25 }
26 }
27
28 public void cubeToSolver() throws NotAvailableException {
29 int[] cubeletPerm = null;
30 int[] cubeletOri = null;
31 int[] faceOri = null;
32
33 cubeletPerm = CubeConfiguration.getStartCubeletPerm();
34 cubeletOri = CubeConfiguration.getStartCubeletOri();
35 faceOri = CubeConfiguration.getStartFaceOri();
36
37 if (cubeletPerm != null && cubeletOri != null && faceOri != null) {
38
39 int[] cubeletPerm2 = deepCopy(cubeletPerm);
40 int[] cubeletOri2 = deepCopy(cubeletOri);
41 int[] faceOri2 = deepCopy(faceOri);
42
43 cubie.cubieSetCube(cubeletPerm2, cubeletOri2, faceOri2);
44
45 System.out.println("Cube-configuration was sent to the solver.");
46 if (!cubie.getT()) {
47 System.err
48 .println("ERROR: The present cube-configuration " + "seems unsolvable.");
49 /*
50 * The "t"-variable from Cubie implies more or less, that the specified
51 * cube-configuration is solvable or not. DISCLAIMER: The t-variable
52 * should not be fully trusted, it can appear unchanged while the
53 * configuration is unsolvable, then Cubie crashes.
54 */
55 }
56 } else {
57 throw new NotAvailableException("cube-configuration", "See tab [CUBE].");
58 }
59 }
60
61 // Static method:
62 /** Deep copy instead of shallow copying. */
63 public static int[] deepCopy(int[] array1) {
64 int[] array2 = new int[array1.length];
65
66 for (int q = 0; q < array1.length; q++) {

Pagina 89 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_SOLV_CubeToSolverListener

67 array2[q] = array1[q];
68 }
69 return array2;
70 }
71 }

Pagina 90 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_SOLV_EnumerateMovesListener

1 package listeners.solv;
2
3 import java.awt.event.*;
4
5 import model.CommandSeq;
6 import model.CommonObjects;
7 import solver.solverJS.viewSolverJS.Cubie;
8 import solver.solverJS.algorithm.MoveSequence;
9
10 public class B_SOLV_EnumerateMovesListener implements ActionListener {
11
12 private Cubie cubie;
13
14 // Constructor:
15 public B_SOLV_EnumerateMovesListener() {
16 this.cubie = CommonObjects.getCubie();
17 }
18
19 // Instance method:
20 public void actionPerformed(ActionEvent e) {
21
22 MoveSequence moveSeq = cubie.getMoveSeqGenerator();
23
24 if (moveSeq != null) {
25
26 CommandSeq.setSolutionCommandsMatrix(moveSeq.getMoves(), moveSeq.getAmount(),
27 moveSeq.getLength());
28
29 System.out.println(CommandSeq.solutionCommandsMatrixToString());
30 System.out.println("End of movesequence.");
31 }
32 }
33 }

Pagina 91 van 329 CubeThesis™ Depamelaere-Deschuytter


class B_SOLV_MoveSeqToRobotListener

1 package listeners.solv;
2
3 import java.awt.event.*;
4
5 import model.CommandSeq;
6 import model.CommonObjects;
7 import model.CBTHSettingsList;
8 import solver.solverJS.algorithm.*;
9 import solver.solverJS.viewSolverJS.Cubie;
10
11 public class B_SOLV_MoveSeqToRobotListener implements ActionListener {
12
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14 private Cubie cubie;
15
16 // Constructor:
17 public B_SOLV_MoveSeqToRobotListener(Cubie cubie) {
18 this.cubie = cubie;
19 }
20
21 // Instance methods:
22 public void actionPerformed(ActionEvent e) {
23
24 moveSeqToRobot();
25 }
26
27 public void moveSeqToRobot() {
28 /*
29 * The movesequence, returning from Cubie, is arranged from solved state to
30 * the problem-situation. (Rather a generating than a solving sequence) Our
31 * logic will invert the sequence.
32 */
33 MoveSequence moveSeq = cubie.getMoveSeqGenerator();
34
35 if (moveSeq != null) {
36
37 int len = moveSeq.getLength();
38 int[] moves = moveSeq.getMoves();
39 int[] amount = moveSeq.getAmount();
40
41 CommandSeq.setSolutionCommandsMatrix(moves, amount, len);
42
43 if (cbthsl.getBoolean("updateVisualizationWithRobot")) {
44 // Synchronize Cubie's viewer with the startpostion of the robot:
45 CommandSeq.setRobotPositionHor(0);
46 CommandSeq.setRobotPositionVer(0);
47 cubie.viewerBackToBegin();
48 }
49 /*
50 * The robot has it's queue of instructions, and can take these commands
51 * at its own pace.
52 */
53 CommandSeq.addNewCommand(7);
54 CommandSeq.solutionCommandsMatrixToQueue();
55 CommandSeq.addNewCommand(7);
56 }
57 }
58 }

Pagina 92 van 329 CubeThesis™ Depamelaere-Deschuytter


class Main

1 package main;
2
3 import java.io.*;
4 import java.lang.reflect.Field;
5 import javax.swing.*;
6
7 import cbthFileChooser.FileIO;
8 import exceptions.NotAvailableException;
9 import model.*;
10 import view.TransparentSplashScreen;
11 import view.ViewCubeThesis;
12
13 public class Main {
14
15 /**
16 * The main()-method is the first method that is invoked, when a Javaprogram
17 * is started. One could refer to the 'Big Bang' in space.
18 */
19 public static void main(String[] args) {
20
21 long startTime = System.currentTimeMillis();
22
23 /*
24 * The idea is to spawn the splashscreen as early as possible when booting
25 * the program. Nevertheless, first the CBTHSettingsList is created, because
26 * it's needed for the SplashScreen's creation.
27 */
28 CBTHSettingsList cbthsl = new CBTHSettingsList();
29
30 // Create & spawn Splashscreen:
31 TransparentSplashScreen tss = new TransparentSplashScreen(cbthsl,
32 new String[] { "img", "icon", "Splashscreen.png" });
33 tss.setVisible(true);
34
35 // Update CBTHSettings with textFile (if available):
36 cbthsl.importCBTHSettingsFromTXT();
37
38 // Will alter between the OS/Java-LookAndFeel, nothing but the
39 // general appearance of visual-things changes:
40 try {
41 if (cbthsl.getBoolean("cbthGUITakesOSLook")) {
42 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
43 } else {
44 UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
45 }
46 } catch (Exception exp) {
47 System.err.println("ERROR: Unexpected error has occurred during modifying "
48 + "the UI-Manager. Our apologies for the inconvenience.");
49 }
50
51 // While the SplashScreen's active, further creation of objects
52 // is continued:
53 new CommonObjects(cbthsl);
54 CBTHImagesList imgl = new CBTHImagesList();
55 CubeFacesList cfl = new CubeFacesList();
56 new FileIO(imgl, cfl);
57
58 // Extra locations to seek for OS-dependent/native libraries are
59 // added to the default path:
60 try {
61 addLibrary(whichOSDepLibrary(cbthsl));
62 } catch (IOException ioe) {
63
64 }
65
66 // The visual main window will be created, but not yet shown to the user:

Pagina 93 van 329 CubeThesis™ Depamelaere-Deschuytter


class Main

67 ViewCubeThesis v = new ViewCubeThesis(imgl, cfl);


68
69 // Splashscreen will last at least for 4 secs.
70 while (System.currentTimeMillis() - startTime < 4000) {
71 try {
72 Thread.sleep(500);
73 } catch (InterruptedException e) {
74 e.printStackTrace();
75 }
76 }
77
78 tss.setVisible(false);
79
80 // The already made ViewCubeThesis-window is launched, by setting
81 // it visible.
82 v.setVisible(true);
83
84 // Check for missing files/libraries.
85 String pathStructure[][] = { { "ExtLib", "OpenCV", "opencv-310.jar" },
86 { "ExtLib", "OpenCV", "Windows", "x64", "opencv_java310.dll" },
87 { "ExtLib", "OpenCV", "Windows", "x86", "opencv_java310.dll" },
88 { "ExtLib", "BlenderGUICBTH", "BlenderGUICBTH.exe" },
89 { "doc", "overview-summary.html" } };
90 String temporaryPath = null;
91 File temporaryFile = null;
92
93 // The line below, will print the library locations on the
94 // java.library.path. (For checking purposes)
95 // System.out.println(System.getProperty("java.library.path"));
96
97 for (int i = 0; i < pathStructure.length; i++) {
98 temporaryPath = cbthsl.makeSysIndepFilePath(pathStructure[i], 2);
99 try {
100 temporaryFile = new File(temporaryPath);
101 if (!temporaryFile.exists()) {
102 throw new NotAvailableException(temporaryFile.getName() + "-library/file",
103 "Fix the missing libray/file at location: " + temporaryPath);
104 }
105 } catch (NotAvailableException nae) {
106 System.err.println(nae);
107 }
108 temporaryPath = null;
109 temporaryFile = null;
110 }
111
112 long endTime = System.currentTimeMillis();
113
114 // When user gets the following message, the program is ready.
115 System.out.println("Welcome to CubeThesis 2015-2016, the program got l" + "oaded in "
116 + (endTime - startTime) + " milliseconds!");
117 }
118
119 // Static methods:
120 public static void addLibrary(String s) throws IOException {
121 // This method will make the requested libraries available for
122 // interaction with the camera later on.
123 // Source: http://nicklothian.com/blog/2008/11/19/
124 // modify-javalibrarypath-at-runtime/ visited the 3/11/2015.
125
126 try {
127 // This enables the java.library.path to be modified at runtime
128 // From a Sun engineer at
129 // http://forums.sun.com/thread.jspa?threadID=707176
130 Field field = ClassLoader.class.getDeclaredField("usr_paths");
131 field.setAccessible(true);
132 String[] paths = (String[]) field.get(null);

Pagina 94 van 329 CubeThesis™ Depamelaere-Deschuytter


class Main

133
134 for (int i = 0; i < paths.length; i++) {
135 if (s.equals(paths[i])) {
136 return;
137 }
138 }
139
140 String[] tmp = new String[paths.length + 1];
141 System.arraycopy(paths, 0, tmp, 0, paths.length);
142 tmp[paths.length] = s;
143 field.set(null, tmp);
144 System.setProperty("java.library.path",
145 System.getProperty("java.library.path") + File.pathSeparator + s);
146
147 } catch (IllegalAccessException iae) {
148 throw new IOException("ERROR: Failed to get permissions to set " + "library path");
149 } catch (NoSuchFieldException nsfe) {
150 throw new IOException("ERROR: Failed to get field handle to set " + "library path");
151 }
152 }
153
154 /**
155 * This method will generate the location of the OpenCV-resources, by checking
156 * for OS-type and Java-bitness.
157 */
158 public static String whichOSDepLibrary(CBTHSettingsList cbthsl) {
159 // Source: http://stackoverflow.com/questions/18269570/
160 // how-to-package-opencv-java-in-a-jar
161 // visited the 3/11/2015
162
163 String libraryPath = null;
164 String osName = System.getProperty("os.name");
165 System.out.print("Computer OS: " + osName + " Bitness of running Java-version: ");
166
167 if (osName.startsWith("Windows")) {
168 int bitness = Integer.parseInt(System.getProperty("sun.arch.data.model"));
169 System.out.println(bitness);
170
171 if (bitness == 32) {
172 // System.out.println("32 bit detected");
173 String[] filePathComp = { "ExtLib", "OpenCV", "Windows", "x86" };
174 libraryPath = cbthsl.makeSysIndepFilePath(filePathComp, 2);
175 } else if (bitness == 64) {
176 // System.out.println("64 bit detected");
177 String[] filePathComp = { "ExtLib", "OpenCV", "Windows", "x64" };
178 libraryPath = cbthsl.makeSysIndepFilePath(filePathComp, 2);
179 } else {
180 // System.out.println("Unknown bit detected - trying with 32 bit");
181 String[] filePathComp = { "ExtLib", "OpenCV", "Windows", "x86" };
182 libraryPath = cbthsl.makeSysIndepFilePath(filePathComp, 2);
183 }
184 } else if (osName.equals("Mac OS X")) {
185 System.err.println("ERROR: Probably CubeThesis is running on an "
186 + "Apple-computer. The library responsible for camera-connection "
187 + "was not provided. Howerver all other functionality is supported. "
188 + "Our apologies for the inconvience.");
189 } else {
190 System.err.println("ERROR: Probably CubeThesis is not running from "
191 + "a Windows-computer, camera-connection is therefore not guaranteed."
192 + " All other functionality is supported. Our apologies for the "
193 + "inconvenience.");
194 }
195 return libraryPath;
196 }
197 }

Pagina 95 van 329 CubeThesis™ Depamelaere-Deschuytter


class AutomaticRoutine

1 package model;
2
3 import connection.conWithCamera.CamTakePicture;
4 import connection.conWithRobot.CommunicationRobotThread;
5 import exceptions.*;
6 import listeners.cam.T_CAM_LiveStreamItemListener;
7 import listeners.solv.*;
8 import solver.solverJS.viewSolverJS.Cubie;
9 import solver.solverJS.algorithm.CubieSettings;
10 import view.ViewTabPanel4Aut;
11
12 public class AutomaticRoutine extends Thread {
13
14 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
15 private static volatile boolean[] subtasksNecessary = { true, true, true, true };
16 /*
17 * These subtasks are: - [1] Read cube - [2] Build virtual cube - [3] Solve
18 * algorithmic - [4] Send solution
19 */
20 private static volatile boolean routineNotAborted;
21 private CommunicationRobotThread comRobot;
22 private T_CAM_LiveStreamItemListener camLSIL;
23 private Cubie cubie;
24 private B_SOLV_CubeToSolverListener cubeToSolver;
25 private CBTHImagesList imgl;
26 private CubeFacesList cfl;
27 private ViewTabPanel4Aut vtpa;
28
29 // Constructor:
30 public AutomaticRoutine(CBTHImagesList imgl, CubeFacesList cfl, ViewTabPanel4Aut vtpa) {
31
32 this.imgl = imgl;
33 this.cfl = cfl;
34 this.vtpa = vtpa;
35
36 routineNotAborted = true;
37 comRobot = CommonObjects.getCommunicatieRobot();
38 camLSIL = CommonObjects.getCamLSIL();
39 cubie = CommonObjects.getCubie();
40 cubeToSolver = CommonObjects.getCubeToSolver();
41 }
42
43 // Setters:
44 public static void setSubTaskNecessary(int index, boolean necessary) {
45 subtasksNecessary[index] = necessary;
46 }
47
48 public static void setRoutineNotAborted(boolean continueOrStop) {
49 routineNotAborted = continueOrStop;
50
51 System.out.println("Boolean \"routineNotAborted\" was updated: " + continueOrStop);
52 }
53
54 /**
55 * This run-method implements the whole automatic process. It is coupled to
56 * the most powerful button in CubeThesis.
57 */
58 public void run() {
59
60 long startTime = System.currentTimeMillis();
61
62 // Setting the icons off at the beginning:
63 for (int index = 0; index < subtasksNecessary.length; index++) {
64 boolean onOff = true;
65 if (subtasksNecessary[index])
66 onOff = false;

Pagina 96 van 329 CubeThesis™ Depamelaere-Deschuytter


class AutomaticRoutine

67 vtpa.setLogoOnOffVtspa(index, onOff);
68 }
69
70 /*
71 * Start (if not already started) the communicationServer that handles the
72 * communication with the robotcontroller.
73 */
74 if (!comRobot.getLinkRobotEstablished()) {
75
76 if (!comRobot.isAlive()) {
77 comRobot.start();
78 }
79 comRobot.initializeCommunicationRobot();
80 }
81
82 /*
83 * At this point the procedure waits till connection with the intended
84 * robot-device was put up. "routineNotAborted" is passed to let the user
85 * stop the waiting.
86 */
87 while (!comRobot.getLinkRobotEstablished() && routineNotAborted) {
88 try {
89 Thread.sleep(500);// 1000 milliseconds is one second.
90 } catch (InterruptedException ex) {
91 Thread.currentThread().interrupt();
92 }
93 }
94
95 // PHASE [1]: Read cube
96 if (subtasksNecessary[0] && routineNotAborted) {
97
98 // Connect to the Camera-device:
99 if (!camLSIL.getLinkCamEstablished()) {
100 camLSIL.connectToCapDevice();
101 // Wait 3 seconds to let the camera accomodate:
102 // Omitting this would yield for discoloured images.
103 try {
104 Thread.sleep(3000);
105 } catch (InterruptedException ex) {
106 Thread.currentThread().interrupt();
107 }
108 }
109
110 /*
111 * Not every CBTHImage is suited to perform solid color-estimation. If the
112 * lowest confidence- level of the obtained CubeFace is below the
113 * "thresholdColorEstimation", a new CBTHImage will be processed. When the
114 * six mainCubeFaces got a reliable CubeFace, this task is considered
115 * accomplished. When 15 attempts fail to provide a proper CubeFace, the
116 * process is also halted, since there's another issue somewhere and
117 * further continuation makes no sense.
118 */
119
120 // This array knows how to 'topple' the cube, during reading in.
121 int[] toppleArray = cbthsl.getIntArray("cubeReadingToppleArray");
122 CBTHImage img = null;
123 CubeFace cf = null;
124 int attemptsForColorEstimation = 0;
125 double thresholdColorEstimation = cbthsl.getDouble("thresholdColorEstimation");
126
127 /*
128 * mainCubeFaceRotationArray: knows how to rotate the respective CubeFace
129 * before assignment to some mainCubeFace: 1 = 90° clockwise, -1 = 90°
130 * counterclockwise, 2 = 180° (counter)clockwise.
131 */
132 int[] mainCubeFaceRotationArray = cbthsl.getIntArray("cubeReadingMCFRotationArray");

Pagina 97 van 329 CubeThesis™ Depamelaere-Deschuytter


class AutomaticRoutine

133
134 /*
135 * The first processed face will be assigned to the mainCubeFace-index at
136 * the first field of the array below etc. These are the indexes of the
137 * mainCubeFaces: {0=LeftFace, 1=UpperFace, 2=FrontFace, 3=RightFace,
138 * 4=DownFace, 5=BackFace}. So if index 0 from the mainCubeFaceAssignArray
139 * contains 3, then the actual CubeFace is assigned to "RightFace" of the
140 * cube.
141 */
142 int[] mainCubeFaceAssignArray = cbthsl.getIntArray("cubeReadingMCFAssignArray");
143
144 int rotationToApply = 0;
145 int whichMainCubeFace = 0;
146 int originalAmountSamplesPerFacelet = cbthsl.getInt("amountOfSamplesPerFacelet");
147
148 try {
149 int i = 0;
150 while (i < 6 && routineNotAborted) {
151 // After a 'topple'-move, the attemptsForColorEstimation
152 // is reset.
153 attemptsForColorEstimation = 0;
154 do {
155 img = CamTakePicture.takePicture();
156 // Mainsamples are even incremented,
157 // if a bad Color-estimation preceeded:
158 cbthsl.setInt("amountOfSamplesPerFacelet",
159 (originalAmountSamplesPerFacelet + attemptsForColorEstimation));
160 cf = ColorEstimation.colorRecognition(img);
161 attemptsForColorEstimation++;
162
163 } while (!cf.confidenceLevelSufficient(thresholdColorEstimation)
164 && attemptsForColorEstimation < 15 && routineNotAborted);
165
166 // Reset the amountOfSamples, for the next CubeFace:
167 cbthsl.setInt("amountOfSamplesPerFacelet", (originalAmountSamplesPerFacelet));
168
169 if (i < 5) {
170 // New topple instruction is added to the robot's queue:
171 CommandSeq.addNewCommand(toppleArray[i]);
172
173 try {
174 Thread.sleep(1000); // 1 sec should be sufficient
175 // for the robotIsBusy-field to become true.
176 } catch (InterruptedException ex) {
177 Thread.currentThread().interrupt();
178 }
179
180 while (comRobot.getRobotIsBusy()) {
181 try {
182 Thread.sleep(250);
183 // To lose a minimum of time, the robot is
184 // checked at 4Hz.
185 } catch (InterruptedException ex) {
186 Thread.currentThread().interrupt();
187 }
188 }
189 }
190
191 if (cf != null) {
192
193 imgl.addCBTHImage(img);
194
195 // The acquired CubeFace is assigned to the right
196 // mainCubeFace with the right orientation.
197
198 // Four times 90° implies no move => syntax "%" used as

Pagina 98 van 329 CubeThesis™ Depamelaere-Deschuytter


class AutomaticRoutine

199 // the modulo division.


200 rotationToApply = mainCubeFaceRotationArray[i] % 4;
201
202 switch (rotationToApply) {
203 case 1:
204 cf.rotateCubeFace(true);
205 break; // 90° CLKW
206 case 2:
207 cf.rotateCubeFace(true);
208 cf.rotateCubeFace(true);
209 break; // 180° CLKW
210 case 3:
211 cf.rotateCubeFace(false);
212 break; // 90° CNTRCLKW
213 default:
214 break;
215 }
216
217 // The CubeFace is added to the cubeFacesList
218 // (the lowest one):
219 cfl.addCubeFace(cf);
220
221 // The CubeFace is assigned to the respective
222 // mainCubeFace:
223 whichMainCubeFace = mainCubeFaceAssignArray[i];
224 cfl.getMainCubeFace(whichMainCubeFace)
225 .setCubeFaceDeepCopy(cf.getColorsMatrix(), cf.getConfidenceMatrix());
226 }
227
228 rotationToApply = 0;
229 whichMainCubeFace = 0;
230 cf = null;
231 i++;
232 }
233
234 } catch (NoCaptureDevConnectionException ncdce) {
235 System.err.println(ncdce);
236 }
237 vtpa.setLogoOnOffVtspa(0, true);
238 }
239
240 // PHASE [2]: Build virtual cube
241 if (subtasksNecessary[1] && routineNotAborted) {
242
243 // Reset the virtual cube array's:
244 CubeConfiguration.setStartCubeletPerm(null);
245 CubeConfiguration.setStartCubeletOri(null);
246 CubeConfiguration.setStartFaceOri(null);
247
248 try {
249 CubeConfiguration.buildVirtualCube(cfl.getAllMainCubeFaces());
250 vtpa.updateVirtCubeSubPanel();
251 vtpa.setLogoOnOffVtspa(1, true);
252
253 } catch (FaceletColorNoneException fcne) {
254 System.err.println(fcne);
255 } catch (NonExistingCubeletException nece) {
256 System.err.println(nece);
257 } catch (CubeletAlreadyAssignedException caae) {
258 System.err.println(caae);
259 }
260 }
261
262 // PHASE [3]: Solve algorithmic
263 if (subtasksNecessary[2] && routineNotAborted) {
264

Pagina 99 van 329 CubeThesis™ Depamelaere-Deschuytter


class AutomaticRoutine

265 /*
266 * What is taken into account solving the cube: 1) Experience learned that
267 * asking Cubie for another solve, mostly yields for a shorter solution.
268 * 2) The time spent to solve the algorithm is restricted by the user, by
269 * means of the CBTHSetting: timeToSolveAlgorithm [sec]. 3) If the pc is
270 * too occupied, hence not reaching a single solution in the restricted
271 * time, we allow Cubie to calculate longer only for the first solution.
272 * 4) Some solvers of Cubie sense when they can't come up with any shorter
273 * solution by reporting number '3'. Further iterations to spend the
274 * timeToSolveAlgorithm won't make sense. This has nothing to do with the
275 * mathematical existence of a shorter solution!
276 *
277 * NOTE: It's not very clever to increase the timeToSolve severely, since
278 * Cubie will probably spend way more time solving for a shorter sequence,
279 * than the robot would spend to perform some extra moves.
280 */
281
282 try {
283 int timeToSolveAlgorithm = cbthsl.getInt("timeToSolveAlgorithm");
284 cubeToSolver.cubeToSolver();
285
286 CubieSettings cubieSettings = cubie.getSettings();
287 long startTimeSolving = System.currentTimeMillis();
288 long endTimeSolving = startTimeSolving;
289
290 // No matter the "timeToSolveAlgorithm",
291 // the process awaits at least one solution for the cube.
292 cubie.solve();
293 do {
294 try {
295 Thread.sleep(250);
296 } catch (InterruptedException ex) {
297 Thread.currentThread().interrupt();
298 }
299 /* Check wheter the solver is still running. */
300 } while (cubieSettings.solving &&
301 /* cubieSettings.lastOutputSolver != 4 && */ routineNotAborted);
302
303 /*
304 * cubieSettings.lastOutputSolver: 0 = Initialisation done 1 = Solution
305 * found 2 = Solver aborted by user 3 = Solver finished, no solution
306 * found 4 = Solver is solving
307 */
308
309 // If routineNotAborted has not interfered,
310 // CubeThesis now disposes of a cube-solution if
311 // the cube was solvable.
312 endTimeSolving = System.currentTimeMillis();
313 int solveAttempt = 2;
314
315 while ((endTimeSolving - startTimeSolving) < timeToSolveAlgorithm * 1000
316 && routineNotAborted && cubieSettings.lastOutputSolver != 3) {
317 System.out.println("There is still time left considering the "
318 + "\"timeToSolveAlgorithm\"-setting: "
319 + "Possibility of other solutions is checked..." + " [Attempt "
320 + solveAttempt + "] Time spent/" + "maxTimeAllowed: "
321 + (System.currentTimeMillis() - startTimeSolving + "/"
322 + timeToSolveAlgorithm * 1000 + " [ms/ms]."));
323 cubie.solve();
324
325 do {
326 try {
327 Thread.sleep(250);
328 // At "4Hz" this thread wonders whether the solver
329 // has finished.
330 } catch (InterruptedException ex) {

Pagina 100 van 329 CubeThesis™ Depamelaere-Deschuytter


class AutomaticRoutine

331 Thread.currentThread().interrupt();
332 }
333 endTimeSolving = System.currentTimeMillis();
334 } while (cubie.getSettings().solving
335 && (endTimeSolving - startTimeSolving) < timeToSolveAlgorithm * 1000
336 && routineNotAborted);
337
338 endTimeSolving = System.currentTimeMillis();
339 solveAttempt++;
340 }
341
342 /*
343 * The sourcecode cubie.solve() in the if(){} below seems not
344 * appropriate at first sight. However, the .solve() method stops all
345 * Cubie's solvers if some solver was busy. In manual mode, you click
346 * the solvebutton to stop a solver at runtime, but then the solvebutton
347 * shows the text "stop". But the same solve() method is invoked
348 * internally to stop the solvers.
349 */
350 if (cubie.getSettings().solving) {
351 cubie.solve();
352 }
353 vtpa.setLogoOnOffVtspa(2, true);
354
355 } catch (NotAvailableException nae) {
356 System.err.println(nae);
357 }
358 }
359
360 // PHASE [4]: Send solution
361 if (subtasksNecessary[3] && routineNotAborted) {
362 vtpa.updateSendSolutionSubPanel();
363 CommonObjects.getMoveSeqToRobot().moveSeqToRobot();
364 }
365
366 while (CommandSeq.getQueueSize() > 0) {
367 try {
368 Thread.sleep(500);// At "2Hz" this thread wonders whether
369 // the robot has finished.
370 } catch (InterruptedException ex) {
371 Thread.currentThread().interrupt();
372 }
373 }
374 vtpa.setLogoOnOffVtspa(3, true);
375
376 long endTime = System.currentTimeMillis();
377
378 // Close camera link:
379 if (camLSIL.getLinkCamEstablished()) {
380 camLSIL.disconnectFromCapDevice();
381 }
382
383 AutomaticRoutine.routineNotAborted = false;
384 System.out.println("De tasks of the automatic routine have been completed in: "
385 + (endTime - startTime) + "[ms].");
386 }
387 }

Pagina 101 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHImage

1 package model;
2
3 import java.awt.image.*;
4 import java.io.*;
5 import javax.imageio.ImageIO;
6
7 import cbthFileChooser.Utils;
8
9 public class CBTHImage {
10
11 private static int iDGenerator = 0;
12 private int iD;
13 private String imgName;
14 private BufferedImage imgOriginal;
15 private BufferedImage imgCropped;
16 private int croppedXPos;
17 private int croppedYPos;
18 private int croppedWidth;
19 private int croppedHeight;
20
21 /**
22 * Default-constructor, mere a formality since this one is of no pratical use.
23 */
24 public CBTHImage() {
25
26 this.iD = iDGenerator;
27 this.imgName = null;
28 this.imgOriginal = null;
29 this.imgCropped = null;
30
31 this.croppedXPos = 0;
32 this.croppedYPos = 0;
33 this.croppedWidth = 0;
34 this.croppedHeight = 0;
35
36 iDGenerator++;
37 }
38
39 /**
40 * This constructor is called for to create a new CBTHImage from the capture
41 * device's output.
42 *
43 * @param imgName
44 * The name of the image
45 * @param original
46 * The image itself
47 */
48 public CBTHImage(String imgName, BufferedImage original) {
49
50 this.iD = iDGenerator;
51 this.imgName = imgName;
52
53 try {
54 this.imgOriginal = original;
55
56 // The three lines of source code below show how to create a
57 // "deep-copy" of a BufferedImage, equivalent to
58 // "=imgOriginal.getSubImage
59 // (0,0,original.getWidth(),original.getHeight())".
60 ColorModel cm = imgOriginal.getColorModel();
61 boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
62 WritableRaster raster = imgOriginal.copyData(null);
63
64 this.imgCropped = new BufferedImage(cm, raster, isAlphaPremultiplied, null);
65
66 this.croppedXPos = 0;

Pagina 102 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHImage

67 this.croppedYPos = 0;
68 this.croppedWidth = imgOriginal.getWidth();
69 this.croppedHeight = imgOriginal.getHeight();
70
71 } catch (Exception e) {
72 System.err.println("ERROR: During creation of a new CBTHImage, "
73 + "an unexpected error occurred. Our apologies for the " + "inconvenience.");
74 }
75 iDGenerator++;
76 }
77
78 /**
79 * When images are loaded into the session, either from a CubeThesisProject or
80 * via the "Browse img..."-button; this constructor is called for.
81 *
82 * @param original
83 * By preference the original image is loaded because it allows for
84 * adjusting the cropframe to get a bigger image.
85 * @param cropped
86 * If the original data is lost, than the cropped image can be loaded
87 * if available. Further cropping is only possible by means of
88 * shrinking the image.
89 * @param x
90 * x-co of the crop-frame
91 * @param y
92 * y-co of the crop-frame
93 * @param w
94 * width of the crop-frame
95 * @param h
96 * height of the crop-frame
97 */
98 public CBTHImage(File original, File cropped, int x, int y, int w, int h) {
99
100 this.iD = iDGenerator;
101 try {
102
103 if (original != null && original.exists()) {
104 this.imgName = omitFileExtension(original.getName());
105 this.imgOriginal = ImageIO.read(original);
106 } else {
107 // We suppose cropped != null & exists...
108 this.imgName = omitFileExtension(cropped.getName());
109 this.imgOriginal = ImageIO.read(cropped);
110
111 // If no original file was supplied, original crop-parameters
112 // make no sense anymore.
113 x = 0;
114 y = 0;
115 w = imgOriginal.getWidth();
116 h = imgOriginal.getHeight();
117 }
118
119 this.croppedXPos = x;
120 this.croppedYPos = y;
121
122 this.croppedWidth = w;
123 this.croppedHeight = h;
124
125 this.imgCropped = this.imgOriginal.getSubimage(croppedXPos, croppedYPos,
126 croppedWidth, croppedHeight);
127
128 } catch (IOException ioe) {
129 System.err.println("ERROR: During creation "
130 + "of CBTHImage, some IOException occurred. Our apologies "
131 + "for the inconvenience.");
132 }

Pagina 103 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHImage

133
134 iDGenerator++;
135 }
136
137 // Getters:
138 public int getCroppedXPos() {
139 return croppedXPos;
140 }
141
142 public int getCroppedYPos() {
143 return croppedYPos;
144 }
145
146 public int getCroppedHeight() {
147 return croppedHeight;
148 }
149
150 public int getCroppedWidth() {
151 return croppedWidth;
152 }
153
154 public int getHeightOriginal() {
155 return imgOriginal.getHeight();
156 }
157
158 public int getID() {
159 return iD;
160 }
161
162 public static int getIDGenerator() {
163 return iDGenerator;
164 }
165
166 public BufferedImage getImgCropped() {
167 return imgCropped;
168 }
169
170 public BufferedImage getImgOriginal() {
171 return imgOriginal;
172 }
173
174 public String getName() {
175 return imgName;
176 }
177
178 public int getWidthOriginal() {
179 return imgOriginal.getWidth();
180 }
181
182 // Setter:
183 /** Will update the crop-parameters. */
184 public void setNewCropped(int a, int b, int c, int d) {
185
186 croppedXPos = a;
187 croppedYPos = b;
188 croppedWidth = c;
189 croppedHeight = d;
190
191 if ((a + c) <= imgOriginal.getWidth() && (b + d) <= imgOriginal.getWidth()) {
192 imgCropped = imgOriginal.getSubimage(a, b, c, d);
193 }
194 }
195
196 // Instance methods:
197 /**
198 * Saves the physical original/cropped-file of a CBTHImage.

Pagina 104 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHImage

199 *
200 * @param origLocation
201 * The location at which the original image is to be saved.
202 * @param croppedLocation
203 * The location at which the cropped image is to be saved.
204 * @throws IOException
205 */
206 public void cbthImageToImageFile(String origLocation, String croppedLocation)
207 throws IOException {
208
209 String fileName = this.getName() + "." + Utils.jpg;
210
211 ImageIO.write(this.imgOriginal, Utils.jpg, new File(origLocation + fileName));
212 ImageIO.write(this.imgCropped, Utils.jpg, new File(croppedLocation + fileName));
213 System.out.println("CBTHImage: " + this.getName() + " was properly saved.");
214 }
215
216 /**
217 * Saves a CBTHImage to the saveFile.
218 *
219 * @throws IOException
220 */
221 public void cbthImageToSaveFile(DataOutputStream dos, String folderImgOrig,
222 String folderImgCropped) throws IOException {
223
224 String nameImg = "null";
225 if (getImgOriginal() != null) {
226 nameImg = getName();
227 }
228 dos.writeUTF(folderImgOrig + nameImg + "." + Utils.jpg);
229 nameImg = "null";
230
231 if (getImgCropped() != null) {
232 nameImg = getName();
233 }
234 dos.writeUTF(folderImgCropped + nameImg + "." + Utils.jpg);
235 nameImg = "null";
236
237 dos.writeInt(getCroppedXPos());
238 dos.writeInt(getCroppedYPos());
239 dos.writeInt(getCroppedWidth());
240 dos.writeInt(getCroppedHeight());
241 }
242
243 @Override
244 /** Gives a textual representation of a CBTHImage */
245 public String toString() {
246
247 StringBuffer hulp = new StringBuffer();
248 hulp.append(iD + ". ");
249 hulp.append(this.imgName);
250
251 return hulp.toString();
252 }
253
254 // Static method:
255 public static String omitFileExtension(String s) {
256
257 int indexOfDot = s.indexOf(".");
258 return s.substring(0, indexOfDot);
259 }
260 }

Pagina 105 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHImagesList

1 package model;
2
3 import java.io.*;
4 import java.util.*;
5
6 import exceptions.NumberNotFoundException;
7 import model.CBTHImage;
8
9 public class CBTHImagesList extends Observable {
10
11 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
12 private ArrayList<CBTHImage> cbthImagesList;
13 private static String fS = cbthsl.getString("fileSeparator");
14
15 // Constructor:
16 public CBTHImagesList() {
17
18 cbthImagesList = new ArrayList<CBTHImage>();
19 }
20
21 // Getters:
22 public CBTHImage getCBTHImage(int i) {
23 return cbthImagesList.get(i);
24 }
25
26 public List<CBTHImage> getCBTHImages() {
27 return cbthImagesList;
28 }
29
30 public int getSize() {
31 return cbthImagesList.size();
32 }
33
34 // Instance methods:
35 public void addCBTHImage(CBTHImage img) {
36
37 if (img != null) {
38 cbthImagesList.add(img);
39 System.out.println(
40 "Image \"" + img.getName() + "\" was succesfully added to the cbthImagesList.");
41 updateCBTHImages();
42 }
43 }
44
45 public void cbthImagesListToImageFiles() throws IOException {
46 // If the saveToFolders would not exist anymore, they're recreated.
47 String origLocation = cbthsl.makeSysIndepFilePath(new String[] { "ImgOriginal", "" },
48 3);
49 String croppedLocation = cbthsl
50 .makeSysIndepFilePath(new String[] { "ImgCropped", "" }, 3);
51
52 new File(origLocation).mkdirs();
53 new File(croppedLocation).mkdirs();
54
55 for (CBTHImage img : cbthImagesList) {
56 img.cbthImageToImageFile(origLocation, croppedLocation);
57 }
58 }
59
60 public void cbthImagesListToSaveFile(DataOutputStream dos) throws IOException {
61
62 /*
63 * NOTE: To exchange CubeThesisFiles between computers of different OS,
64 * relative references to images may not be saved by use of a system
65 * dependent file-separator (Windows: '\'). By means of a workaround,
66 * file-separators are saved as a textual representation: "/FILESEPARATOR/".

Pagina 106 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHImagesList

67 */
68
69 String fileSeparatorToText = cbthsl.getString("fileSeparatorToText");
70 String folderImgOrig = fileSeparatorToText + "ImgOriginal" + fileSeparatorToText;
71 String folderImgCropped = fileSeparatorToText + "ImgCropped" + fileSeparatorToText;
72
73 for (CBTHImage img : cbthImagesList) {
74 // "For each image in cbthImagesList..."
75 img.cbthImageToSaveFile(dos, folderImgOrig, folderImgCropped);
76 }
77 }
78
79 public void deleteAllCBTHImages() {
80
81 cbthImagesList.clear();
82 updateCBTHImages();
83 }
84
85 public void deleteCBTHImage(int iD) throws NumberNotFoundException {
86
87 cbthImagesList.remove(searchImageOnID(iD));
88 updateCBTHImages();
89 }
90
91 public void cbthImagesListFromSaveFile(DataInputStream dis) throws IOException {
92
93 int amountOfImages = dis.readInt();
94 String fileNameOrig = null;
95 String fileNameCropped = null;
96 File fileOrig = null;
97 File fileCropped = null;
98 File currentProject = cbthsl.getCurrentProject();
99 CBTHImage img = null;
100
101 for (int j = 0; j < amountOfImages; j++) {
102 fileNameOrig = translateFileSeparator(dis.readUTF());
103 fileNameCropped = translateFileSeparator(dis.readUTF());
104
105 fileOrig = new File(currentProject + fileNameOrig);
106 fileCropped = new File(currentProject + fileNameCropped);
107
108 System.out.println("FileIO: import image from path " + fileOrig);
109 int x = -1, y = -1, w = -1, h = -1;
110
111 try {
112 x = dis.readInt();
113 y = dis.readInt();
114 w = dis.readInt();
115 h = dis.readInt();
116 } catch (Exception exc) {
117 System.err.println("ERROR: " + exc);
118 }
119
120 img = new CBTHImage(fileOrig, fileCropped, x, y, w, h);
121
122 // Reset temporary variables for next loop iteration.
123 fileNameOrig = null;
124 fileNameCropped = null;
125 fileOrig = null;
126 fileCropped = null;
127 if (img != null) {
128 addCBTHImage(img);
129 System.out.println("CBTHImage: " + img.getName() + " succesfully imported.");
130 }
131 img = null;
132 }

Pagina 107 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHImagesList

133 }
134
135 public int searchImageOnID(int iD) throws NumberNotFoundException {
136
137 CBTHImage cbthImage = null;
138 boolean alreadyFound = false;
139 int c = 0, s = cbthImagesList.size();
140
141 while (c < s && !alreadyFound) {
142 cbthImage = getCBTHImage(c);
143 if (iD == cbthImage.getID()) {
144 alreadyFound = true;
145 } else {
146 c++;
147 }
148 }
149 if (!alreadyFound) {
150 throw new NumberNotFoundException("the CBTHImagesList");
151 }
152 return c;
153 }
154
155 /**
156 * This method is part of the Observer-Observable technique. It will trigger
157 * its Observers.
158 */
159 public void updateCBTHImages() {
160 // At this point the view is refreshed upon changes in the model
161 // (CBTHImagesList).
162 setChanged();
163 notifyObservers();
164 }
165
166 // Static method:
167 /**
168 * This method will translate a path with the OS-independent file-separator to
169 * a path with a OS-dependent one to practically use the filepath.
170 *
171 * @param path
172 * The path that needs translation.
173 * @return The path with the altered file-separators.
174 */
175 public static String translateFileSeparator(String path) {
176
177 StringBuffer sb = new StringBuffer();
178 String fileSepToText = cbthsl.getString("fileSeparatorToText");
179 int runningIndex = 0, indexfS = path.indexOf(fileSepToText);
180
181 while (indexfS != -1) {
182 sb.append(path.substring(runningIndex, indexfS));
183 sb.append(fS);
184 runningIndex = indexfS + fileSepToText.length();
185 indexfS = path.indexOf(fileSepToText, runningIndex + 1);
186 }
187
188 sb.append(path.substring(runningIndex, path.length()));
189
190 return sb.toString();
191 }
192 }

Pagina 108 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSetting

1 package model;
2
3 import java.util.Observable;
4
5 import view.VisualCBTHSetting;
6
7 public class CBTHSetting extends Observable {
8
9 public static int iDGenerator = 0;
10 private int iD;
11 private String name;
12 private String labelText;
13 private String type;// int, float, double short, long, boolean,
14 // String, intArray, doubleArray, floatArray...
15 private String value;
16 private boolean editable;
17 private String info;
18
19 // Constructors:
20 public CBTHSetting() {
21
22 this.iD = iDGenerator;
23 this.name = null;
24 this.labelText = null;
25 this.type = "String";
26 this.value = "null";
27 this.editable = false;
28 this.info = null;
29
30 iDGenerator++;
31 }
32
33 public CBTHSetting(String name, String labelText, String type, String value,
34 boolean editable, String info) {
35
36 this.iD = iDGenerator;
37 this.name = name;
38 this.labelText = labelText;
39 this.type = type;
40 this.value = value;
41 this.editable = editable;
42 this.info = info;
43
44 iDGenerator++;
45 }
46
47 // Getters:
48 public boolean getEditable() {
49 return editable;
50 }
51
52 public int getiD() {
53 return iD;
54 }
55
56 public String getInfo() {
57 return info;
58 }
59
60 public String getLabelText() {
61 return labelText;
62 }
63
64 public String getName() {
65 return name;
66 }

Pagina 109 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSetting

67
68 public String getType() {
69 return type;
70 }
71
72 public String getValue() {
73 return value;
74 }
75
76 // Setters:
77 /*
78 * Several attribute setters are made private, to make no extern class can
79 * directly call them. The only way to externally adapt settings is by calling
80 * for .setAll() with the advantage of only updating the visualisationCBTHS
81 * once.
82 */
83 public void setAll(String name, String labelText, String type, String value,
84 String info) {
85
86 if (editable) {
87
88 // When the null-object is passed, these fields remain unchanged.
89 setName(name);
90 setLabelText(labelText);
91 setType(type);
92 setValue(value);
93 setInfo(info);
94
95 // Edit possibly several attributes at a time and update Observers
96 // just once!
97 updateVisualCBTHSetting();
98 }
99 }
100
101 private void setInfo(String info) {
102 if (info != null) {
103 this.info = info;
104 }
105 }
106
107 private void setLabelText(String labelText) {
108 if (labelText != null) {
109 this.labelText = labelText;
110 }
111 }
112
113 private void setName(String name) {
114 if (name != null) {
115 this.name = name;
116 }
117 }
118
119 private void setType(String type) {
120 if (type != null) {
121 this.type = type;
122 }
123 }
124
125 private void setValue(String value) {
126 if (value != null) {
127 this.value = value;
128 }
129 }
130
131 // Instance methods:
132 public boolean containsFragment(String textFragment) {

Pagina 110 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSetting

133 boolean booleanToReturn = false;


134 // If specified fragment is found in CBTHSetting's name or labelText,
135 // it is added to the Selection.
136 // Making the if clause, case in-sensitive.
137 String s_Name = name.toLowerCase();
138 String s_LabelText = labelText.toLowerCase();
139 String s_TextFragment = textFragment.toLowerCase();
140
141 if (s_Name.indexOf(s_TextFragment) != -1
142 || s_LabelText.indexOf(s_TextFragment) != -1) {
143 booleanToReturn = true;
144 }
145 return booleanToReturn;
146 }
147
148 public VisualCBTHSetting createVCBTHSetting() {
149
150 VisualCBTHSetting visualCBTHS = new VisualCBTHSetting(this);
151 this.addObserver(visualCBTHS);
152 updateVisualCBTHSetting();
153
154 return visualCBTHS;
155 }
156
157 public String exportCBTHSetting() {
158 String returnString = "[" + name + "][" + labelText + "][" + type + "][" + value
159 + "]";
160 return returnString + numberOfSpaces(95 - returnString.length()) + "[" + info + "]";
161 }
162
163 public static String numberOfSpaces(int amount) {
164 StringBuffer sb = new StringBuffer();
165
166 if (amount < 0) {
167 amount = 5;
168 }
169
170 for (int i = 0; i < amount; i++) {
171 sb.append(" ");
172 }
173 return sb.toString();
174 }
175
176 /**
177 * This method is part of the Observer-Observable technique. It will trigger
178 * its Observers.*/
179 public void updateVisualCBTHSetting() {
180 setChanged();
181 notifyObservers();
182 }
183 }

Pagina 111 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

1 package model;
2
3 import java.awt.Dimension;
4 import java.awt.event.ActionListener;
5 import java.awt.Font;
6 import java.io.*;
7 import java.util.*;
8 import javax.swing.*;
9 import javax.swing.border.BevelBorder;
10
11 import comparators.*;
12 import exceptions.*;
13
14 public class CBTHSettingsList extends Observable {
15
16 private ArrayList<CBTHSetting> cbthSettingsList;
17 /* Another ArrayList for easy editing purposes: */
18 private ArrayList<CBTHSetting> cbthSettingSelection;
19 private String currentSettingsFilter;
20
21 // Tags to interact with CBTHSettingsFile
22 private static final String commentTag = "[Comment]";
23 private static final String settingTag = "[Setting]";
24
25 // Parameter that should be editable by program, but not by user.
26 private static CBTHSetting currentProject;
27
28 // Colordefinitions:
29 private static final String COLORRED = "Red";
30 private static final String COLORBLUE = "Blue";
31 private static final String COLORYELLOW = "Yellow";
32 private static final String COLORORANGE = "Orange";
33 private static final String COLORGREEN = "Green";
34 private static final String COLORWHITE = "White";
35 private static final String COLORNONE = "None";
36 private static final String[] CUBECOLORS = { COLORRED, COLORBLUE, COLORYELLOW,
37 COLORORANGE, COLORGREEN, COLORWHITE, COLORNONE };
38
39 // CBTHSettings, that have a local, easy addressable copy for internal use:
40 private static Font guiFont1Local;
41 private static Font guiFont2Local;
42 private static Font guiFont3Local;
43
44 // Constructor:
45 public CBTHSettingsList() {
46
47 // ArrayList gets initialized.
48 cbthSettingsList = new ArrayList<CBTHSetting>();
49 cbthSettingSelection = new ArrayList<CBTHSetting>();
50 currentSettingsFilter = null;
51
52 // For automatically creating sync-ing JTextfields... from
53 // CBTHSettings below, Fonts should be created first,
54 // since they're already applied at that point.
55 cbthSettingsList.add(
56 new CBTHSetting("guiFont1", "GUI-Font 1:", "Font", "Century Gothic, 0, 12", true,
57 "Font used for most buttons and labels in GUI. "
58 + "Second parameter: 0 = Plain text, 1 = Bold text, "
59 + "2 = Italic text."));
60 cbthSettingsList
61 .add(new CBTHSetting("guiFont2", "GUI-Font 2:", "Font", "Consolas, 0, 12", true,
62 "Font used for console and textfields in GUI. "
63 + "Second parameter: 0 = Plain text, 1 = Bold text, "
64 + "2 = Italic text."));
65 cbthSettingsList
66 .add(new CBTHSetting("guiFont3", "GUI-Font 3:", "Font", "Stencil, 0, 12", true,

Pagina 112 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

67 "Font used to draw user's attention to something. "


68 + "Second parameter: 0 = Plain text, 1 = Bold text, "
69 + "2 = Italic text."));
70 guiFont1Local = getFont("guiFont1");
71 guiFont2Local = getFont("guiFont2");
72 guiFont3Local = getFont("guiFont3");
73
74 // Add CBTHSettings to the cbthSettingsList, who are not
75 // editable and won't show up in the "CBTHSettingsList.txt".
76 // Settings below depend on OS-type / computer on which
77 // CubeThesis runs.
78 cbthSettingsList.add(new CBTHSetting("basicRelativePath", "Basic Relative Path:",
79 "String", new File("").getAbsolutePath(), false,
80 "Filepath referring to the folder from which CubeThesis " + "was started."));
81 cbthSettingsList.add(new CBTHSetting("fileSeparator", "Fileseparator in file paths:",
82 "String", File.separator, false,
83 "OS-specific fileseparator, " + "used to build valid filepaths."));
84 cbthSettingsList.add(
85 new CBTHSetting("fileSeparatorToText", "Textual representation FileSeparator:",
86 "String", "/FILESEPARATOR/", false, "Textual representation of the "
87 + "fileseparator, for platform independent " + "saving purposes."));
88 cbthSettingsList.add(new CBTHSetting("newLine", "Lineseparator \"newLine\":",
89 "String", System.getProperty("line.separator"), false,
90 "OS-specific lineseparator, referred to as a \"newline\" " + "command."));
91
92 // Add remaining CBTHSettings to the list, that are editable.
93 // General settings.
94 cbthSettingsList.add(new CBTHSetting("cbthGUITakesOSLook", "GUI takes OS-Look:",
95 "boolean", "true", true,
96 "Important: This setting will only affect CubeThesis during "
97 + "next reboot. When \"true\", CubeThesis takes the OS-look; "
98 + "when \"false\", the Java-look is applied."));
99 cbthSettingsList.add(new CBTHSetting("consoleRecordsMin",
100 "Min. amount console-records:", "int", "250", true,
101 "Important: This setting will only affect CubeThesis "
102 + "during next reboot. Minimum number of records the "
103 + "console will display. After a flush was performed, "
104 + "the console maintains this number of records."));
105 cbthSettingsList.add(new CBTHSetting("consoleRecordsMax",
106 "Max. amount console-records:", "int", "500", true,
107 "Important: This setting will only affect CubeThesis "
108 + "during next reboot. Maximum number of records the "
109 + "console will display. Records exceeding this limit "
110 + "are flushed away to logfiles."));
111 cbthSettingsList.add(new CBTHSetting("saveCBTHSettingsOnExit",
112 "CBTHSettings saved when quitting:", "boolean", "true", true,
113 "When \"true\", CubeThesis automatically saves its "
114 + "settings when closing the application. When \"false\", "
115 + "a specific button is to be pressed to save the " + "CBTHSettings."));
116
117 // Variables linked to the CubeReading process.
118 cbthSettingsList.add(new CBTHSetting("captureDevice", "Capture device (index):",
119 "String", "0", true, "Specify the preferred camera by index/(name)."));
120 cbthSettingsList.add(new CBTHSetting("ipAddressCamera", "IP-Address cap. device:",
121 "String", "0.0.0.0", true,
122 "Specify the preferred camera's IP-Address (use (hexa)" + "decimal notation)."));
123
124 cbthSettingsList.add(new CBTHSetting("xCoCrop", "Crop parameter x-co:", "int", "0",
125 true, "Determines the x-co of the frame to crop the snapshot."));
126 cbthSettingsList.add(new CBTHSetting("yCoCrop", "Crop parameter y-co:", "int", "0",
127 true, "Determines the y-co of the frame to crop the snapshot."));
128 cbthSettingsList.add(new CBTHSetting("widthCrop", "Crop parameter width:", "int", "0",
129 true, "Determines the width of the frame to crop the snapshot."));
130 cbthSettingsList.add(new CBTHSetting("heightCrop", "Crop parameter height:", "int",
131 "0", true, "Determines the height of the frame to crop the snapshot."));
132

Pagina 113 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

133 cbthSettingsList.add(new CBTHSetting("cubeReadingToppleArray", "\"Topple\" - array:",


134 "intArray", "{0, 0, 0, 0, 0}", true,
135 "Advanced robot-tool-specific setting. Alter only if "
136 + "you thoroughly understand what you're doing. "
137 + "Sequence of topple moves performed " + "between the snapshots."));
138 cbthSettingsList.add(new CBTHSetting("cubeReadingMCFRotationArray",
139 "\"MainCubeFaceRotation\" - array:", "intArray", "{0, 0, 0, 0, 0, 0}", true,
140 "Advanced robot-tool-specific "
141 + "setting. Alter only if you thoroughly understand "
142 + "what you're doing. Sequence of rotations to be applied "
143 + "prior to assigning actual CubeFace to some " + "mainCubeFace."));
144 cbthSettingsList.add(new CBTHSetting("cubeReadingMCFAssignArray",
145 "\"MainCubeFaceAssign\" - array:", "intArray", "{0, 0, 0, 0, 0, 0}", true,
146 "Advanced robot-tool-specific "
147 + "setting. Alter only if you thoroughly understand what "
148 + "you're doing. Sequence to determine which mainCubeFace "
149 + "the actual CubeFace is to be assigned to."));
150
151 // Settings that are options in the process of color recognition.
152 cbthSettingsList.add(new CBTHSetting("extensiveSampleOutprint",
153 "Extensive sample outprint:", "boolean", "false", true,
154 "Will report samples more extensively, when toggled."));
155 cbthSettingsList.add(new CBTHSetting("thresholdColorEstimation",
156 "Threshold colorestimation: (enter < 100) (%):", "double", "75.0", true,
157 "Threshold expressed in (%) that will tell "
158 + "good colorestimations from bad ones apart."));
159 cbthSettingsList
160 .add(new CBTHSetting("amountOfSamplesPerFacelet", "Amount of (main)samples:",
161 "int", "1", true, "The colorestimation, established for each facelet, "
162 + "will require this number of (main)samples to be taken."));
163 cbthSettingsList
164 .add(new CBTHSetting("amountOfSampleAveraging", "Amount of subsamples:", "int",
165 "1", true, "Each (main)sample can be averaged out from a set of "
166 + "subsamples. This parameter specifies the size of that " + "subset."));
167
168 // Settings below are used in color recognition.
169 cbthSettingsList.add(
170 new CBTHSetting("minBrightnessWhite", "Min. brightness white:", "int", "0", true,
171 "Specifies the minimum brightness to consider some sample " + "as white."));
172 cbthSettingsList.add(
173 new CBTHSetting("maxSaturationWhite", "Max. saturation white:", "int", "0", true,
174 "Specifies the maximum saturation to consider some sample " + "as white."));
175 cbthSettingsList.add(
176 new CBTHSetting("maxBrightnessBlack", "Max. brightness black:", "int", "0", true,
177 "Specifies the maximum brightness to consider some sample " + "as black."));
178 cbthSettingsList.add(new CBTHSetting("distinctionRedOrange", "Distinct. Red-Orange:",
179 "int", "0", true, "Parameter to tell red apart from orange. Hue-range "
180 + "was upscaled to 360 arbitrary units."));
181 cbthSettingsList
182 .add(new CBTHSetting("distinctionOrangeYellow", "Distinct. Orange-yellow:", "int",
183 "0", true, "Parameter to tell orange apart from yellow. Hue-range "
184 + "was upscaled to 360 arbitrary units."));
185 cbthSettingsList
186 .add(new CBTHSetting("distinctionYellowGreen", "Distinct. Yellow-Green:", "int",
187 "0", true, "Parameter to tell yellow apart from green. Hue-range "
188 + "was upscaled to 360 arbitrary units."));
189 cbthSettingsList.add(new CBTHSetting("distinctionGreenBlue", "Distinct. Green-Blue:",
190 "int", "0", true, "Parameter to tell green apart from blue. Hue-range "
191 + "was upscaled to 360 arbitrary units."));
192 cbthSettingsList
193 .add(new CBTHSetting("distinctionBluePurple", "Distinct. Blue-Purple:", "int",
194 "0", true, "Parameter to tell blue apart from purple. Hue-range "
195 + "was upscaled to 360 arbitrary units."));
196 cbthSettingsList.add(new CBTHSetting("distinctionPurpleRed", "Distinct. Purple-Red:",
197 "int", "0", true, "Parameter to tell purple apart from red. Hue-range "
198 + "was upscaled to 360 arbitrary units."));

Pagina 114 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

199
200 // Settings that concern algorithmic solving process.
201 cbthSettingsList.add(new CBTHSetting("updateVisualizationWithRobot",
202 "Update visualization w robot:", "boolean", "true", true,
203 "Turn this \"true\" to make the algorimthmic solver's "
204 + "visualization run synchronously with the robot executing "
205 + "the tasks."));
206 cbthSettingsList
207 .add(new CBTHSetting("timeToSolveAlgorithm", "Time to solve algorithm:", "int",
208 "5", true, "Applying a timelimit to spend on solving the algorithm, "
209 + "in automatic mode."));
210 cbthSettingsList.add(new CBTHSetting("ipAddressRobot", "IP-Address robot:", "String",
211 "0.0.0.0", true, "Specify the cooperating robot by IP-Address "
212 + "(only for checking purposes) (use (hexa)decimal " + "notation)."));
213 cbthSettingsList
214 .add(new CBTHSetting("portNmbrServerSocket", "Port Serversocket Robotcom.", "int",
215 "8000", true, "This is the portnumber the serversocket hosted on this "
216 + "pc will use in communication witch the robotcontroller."));
217 cbthSettingsList.add(new CBTHSetting("noValidCommand", "Not valid command:", "int",
218 "0", true, "Robotcommand that is agreed not to be a " + "valid instruction."));
219
220 // Exceptions that are editable, but don't need to be added
221 // to the settingsList.
222 currentProject = new CBTHSetting("currentProject", "Current project:", "String",
223 new File(makeSysIndepFilePath(
224 new String[] { "CubeThesisProjects", "DefaultProject" }, 2))
225 .getAbsolutePath(),
226 true, "Restores the \"DefaultProject\" if not available.");
227 getCurrentProject().mkdirs();
228
229 // Make to start with, all CBTHSettings are selected.
230 cbthSettingSelection.addAll(cbthSettingsList);
231 }
232
233 // Getters:
234 public boolean getBoolean(String settingName) {
235
236 boolean value = false;
237 try {
238 CBTHSetting cbths = null;
239 cbths = seekCBTHSetting(settingName);
240 value = Boolean.parseBoolean(cbths.getValue());
241
242 } catch (NoSuchSettingFoundException nssfe) {
243 System.err.println(nssfe);
244 nssfe.printStackTrace();
245 }
246 return value;
247 }
248
249 public ArrayList<CBTHSetting> getCBTHSettingSelection() {
250 return cbthSettingSelection;
251 }
252
253 public String[] getCubeColors() {
254 return CUBECOLORS;
255 }
256
257 public File getCurrentProject() {
258 return new File(currentProject.getValue());
259 }
260
261 public double getDouble(String settingName) {
262
263 double value = 0.0;
264 try {

Pagina 115 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

265 CBTHSetting cbths = null;


266 cbths = seekCBTHSetting(settingName);
267
268 try {
269 value = Double.parseDouble(cbths.getValue());
270 } catch (NumberFormatException nfe) {
271 System.err.println("ERROR: Value stored in CBTHSetting \"" + cbths.getName()
272 + "\" can't be resolved as [double].");
273 }
274
275 } catch (NoSuchSettingFoundException nssfe) {
276 System.err.println(nssfe);
277 nssfe.printStackTrace();
278 }
279 return value;
280 }
281
282 public double[] getDoubleArray(String settingName) {
283
284 double[] values = null;
285 try {
286 CBTHSetting cbths = null;
287 cbths = seekCBTHSetting(settingName);
288 ArrayList<String> stringComponents = splitStringByCommas(cbths.getValue(), 1, 1);
289 values = new double[stringComponents.size()];
290
291 for (int i = 0; i < stringComponents.size(); i++) {
292 values[i] = Double.parseDouble(stringComponents.get(i));
293 }
294 } catch (NoSuchSettingFoundException nssfe) {
295 System.err.println(nssfe);
296 nssfe.printStackTrace();
297 }
298 return values;
299 }
300
301 public float getFloat(String settingName) {
302
303 float value = 0f;
304 try {
305 CBTHSetting cbths = null;
306 cbths = seekCBTHSetting(settingName);
307
308 try {
309 value = Float.parseFloat(cbths.getValue());
310 } catch (NumberFormatException nfe) {
311 System.err.println("ERROR: Value stored in CBTHSetting \"" + cbths.getName()
312 + "\" can't be resolved as [float].");
313 }
314
315 } catch (NoSuchSettingFoundException nssfe) {
316 System.err.println(nssfe);
317 nssfe.printStackTrace();
318 }
319 return value;
320 }
321
322 public Font getFont(String settingName) {
323
324 Font font = null;
325 try {
326 CBTHSetting cbths = null;
327 cbths = seekCBTHSetting(settingName);
328
329 ArrayList<String> stringComponents = splitStringByCommas(cbths.getValue(), 0, 0);
330 font = new Font(stringComponents.get(0), Integer.parseInt(stringComponents.get(1)),

Pagina 116 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

331 Integer.parseInt(stringComponents.get(2)));
332 // Second argument: 0 = Plain text, 1 = Bold text and 2 =
333 // Italic text.
334
335 } catch (NoSuchSettingFoundException nssfe) {
336 System.err.println(nssfe);
337 nssfe.printStackTrace();
338 }
339 return font;
340 }
341
342 public int getInt(String settingName) {
343
344 int value = 0;
345 try {
346 CBTHSetting cbths = null;
347 cbths = seekCBTHSetting(settingName);
348
349 try {
350 value = Integer.parseInt(cbths.getValue());
351 } catch (NumberFormatException nfe) {
352 System.err.println("ERROR: Value stored in CBTHSetting \"" + cbths.getName()
353 + "\" can't be resolved as [int].");
354 }
355
356 } catch (NoSuchSettingFoundException nssfe) {
357 System.err.println(nssfe);
358 nssfe.printStackTrace();
359 }
360 return value;
361 }
362
363 public int[] getIntArray(String settingName) {
364
365 int[] values = null;
366 try {
367 CBTHSetting cbths = null;
368 cbths = seekCBTHSetting(settingName);
369 ArrayList<String> stringComponents = splitStringByCommas(cbths.getValue(), 1, 1);
370 values = new int[stringComponents.size()];
371
372 for (int i = 0; i < stringComponents.size(); i++) {
373 values[i] = Integer.parseInt(stringComponents.get(i));
374 }
375
376 } catch (NoSuchSettingFoundException nssfe) {
377 System.err.println(nssfe);
378 nssfe.printStackTrace();
379 }
380 return values;
381 }
382
383 public String getString(String settingName) {
384
385 String value = "- No String stored -";
386 try {
387 CBTHSetting cbths = null;
388 cbths = seekCBTHSetting(settingName);
389 value = cbths.getValue();
390 } catch (NoSuchSettingFoundException nssfe) {
391 System.err.println(nssfe);
392 nssfe.printStackTrace();
393 }
394 return value;
395 }
396

Pagina 117 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

397 // Setters.
398 public void setBoolean(String settingName, boolean value) {
399
400 String valueToString = "false";
401 try {
402 CBTHSetting cbths = null;
403 cbths = seekCBTHSetting(settingName);
404
405 if (!cbths.getType().equals("boolean")) {
406 throw new NoMatchingSettingTypeException(settingName, cbths.getType(), "boolean");
407 }
408
409 if (value) {
410 valueToString = "true";
411 }
412
413 cbths.setAll(null, null, null, valueToString, null);
414
415 } catch (NoSuchSettingFoundException nssfe) {
416 System.err.println(nssfe);
417 } catch (NoMatchingSettingTypeException nmste) {
418 System.err.println(nmste);
419 }
420 }
421
422 public void setCurrentProject(File f) {
423 currentProject.setAll(null, null, null, f.getAbsolutePath(), null);
424 }
425
426 public void setDouble(String settingName, double value) {
427 try {
428 CBTHSetting cbths = null;
429 cbths = seekCBTHSetting(settingName);
430
431 if (!cbths.getType().equals("double")) {
432 throw new NoMatchingSettingTypeException(settingName, cbths.getType(), "double");
433 }
434
435 cbths.setAll(null, null, null, value + "", null);
436
437 } catch (NoSuchSettingFoundException nssfe) {
438 System.err.println(nssfe);
439 } catch (NoMatchingSettingTypeException nmste) {
440 System.err.println(nmste);
441 }
442 }
443
444 public void setDoubleArray(String settingName, double[] values) {
445
446 try {
447 CBTHSetting cbths = null;
448 cbths = seekCBTHSetting(settingName);
449
450 if (!cbths.getType().equals("doubleArray")) {
451 throw new NoMatchingSettingTypeException(settingName, cbths.getType(),
452 "doubleArray");
453 }
454
455 StringBuffer sb = new StringBuffer();
456 int i;
457
458 sb.append("{");
459 for (i = 0; i < values.length - 1; i++) {
460 sb.append(values[i] + ", ");
461 }
462

Pagina 118 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

463 sb.append(values[i] + "}");


464 cbths.setAll(null, null, null, sb.toString(), null);
465
466 } catch (NoSuchSettingFoundException nssfe) {
467 System.err.println(nssfe);
468 } catch (NoMatchingSettingTypeException nmste) {
469 System.err.println(nmste);
470 }
471 }
472
473 public void setFloat(String settingName, float value) {
474
475 try {
476 CBTHSetting cbths = null;
477 cbths = seekCBTHSetting(settingName);
478
479 if (!cbths.getType().equals("float")) {
480 throw new NoMatchingSettingTypeException(settingName, cbths.getType(), "float");
481 }
482
483 cbths.setAll(null, null, null, value + "", null);
484
485 } catch (NoSuchSettingFoundException nssfe) {
486 System.err.println(nssfe);
487 } catch (NoMatchingSettingTypeException nmste) {
488 System.err.println(nmste);
489 }
490 }
491
492 public void setFont(String settingName, String font) {
493
494 try {
495 CBTHSetting cbths = null;
496 cbths = seekCBTHSetting(settingName);
497
498 if (!cbths.getType().equals("Font")) {
499 throw new NoMatchingSettingTypeException(settingName, cbths.getType(), "Font");
500 }
501
502 cbths.setAll(null, null, null, font, null);
503
504 } catch (NoSuchSettingFoundException nssfe) {
505 System.err.println(nssfe);
506 } catch (NoMatchingSettingTypeException nmste) {
507 System.err.println(nmste);
508 }
509 }
510
511 public void setInt(String settingName, int value) {
512 try {
513 CBTHSetting cbths = null;
514 cbths = seekCBTHSetting(settingName);
515
516 if (!cbths.getType().equals("int")) {
517 throw new NoMatchingSettingTypeException(settingName, cbths.getType(), "int");
518 }
519
520 cbths.setAll(null, null, null, value + "", null);
521
522 } catch (NoSuchSettingFoundException nssfe) {
523 System.err.println(nssfe);
524 } catch (NoMatchingSettingTypeException nmste) {
525 System.err.println(nmste);
526 }
527 }
528

Pagina 119 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

529 public void setIntArray(String settingName, int[] values) {


530
531 try {
532 CBTHSetting cbths = null;
533 cbths = seekCBTHSetting(settingName);
534
535 if (!cbths.getType().equals("intArray")) {
536 throw new NoMatchingSettingTypeException(settingName, cbths.getType(),
537 "intArray");
538 }
539
540 StringBuffer sb = new StringBuffer();
541 int i;
542
543 sb.append("{");
544 for (i = 0; i < values.length - 1; i++) {
545 sb.append(values[i] + ", ");
546 }
547
548 sb.append(values[i] + "}");
549 cbths.setAll(null, null, null, sb.toString(), null);
550
551 } catch (NoSuchSettingFoundException nssfe) {
552 System.err.println(nssfe);
553 } catch (NoMatchingSettingTypeException nmste) {
554 System.err.println(nmste);
555 }
556 }
557
558 public void setString(String settingName, String value) {
559
560 try {
561 CBTHSetting cbths = null;
562 cbths = seekCBTHSetting(settingName);
563
564 if (!cbths.getType().equals("String")) {
565 throw new NoMatchingSettingTypeException(settingName, cbths.getType(), "String");
566 }
567 cbths.setAll(null, null, null, value, null);
568
569 } catch (NoSuchSettingFoundException nssfe) {
570 System.err.println(nssfe);
571 } catch (NoMatchingSettingTypeException nmste) {
572 System.err.println(nmste);
573 }
574 }
575
576 // Instance methods:
577 /*
578 * These methods save some repetitive work for the views, but there's no need
579 * to host them in this particular Class.
580 */
581 public JFrame createCubeThesisFrame(String title) {
582
583 JFrame f = new JFrame();
584 f.setTitle(title);
585
586 String[] pathComp = { "img", "icon", "RubiksCube16x16.png" };
587 String iconPath = makeSysIndepFilePath(pathComp, 2);
588 ImageIcon frameCubeThesisLogo = new ImageIcon(iconPath);
589 f.setIconImage(frameCubeThesisLogo.getImage());
590
591 f.pack();
592 return f;
593 }
594

Pagina 120 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

595 public JButton createJButton(String text, String tooltip, ActionListener actionList) {


596 JButton jb = new JButton(text);
597 jb.setFont(guiFont1Local);
598 jb.setToolTipText(tooltip);
599
600 if (actionList != null) {
601 jb.addActionListener(actionList);
602 }
603 return jb;
604 }
605
606 public JCheckBox createJCheckBox(String text, boolean selected, String tooltip) {
607 JCheckBox ch = new JCheckBox();
608 ch.setText(text);
609 ch.setFont(guiFont1Local);
610 ch.setToolTipText(tooltip);
611 ch.setSelected(selected);
612 return ch;
613 }
614
615 public JLabel createJLabel(String text, int font) {
616 JLabel l = new JLabel(text);
617
618 Font fontToApply;
619
620 switch (font) {
621 case 1:
622 fontToApply = guiFont1Local;
623 break;
624 case 2:
625 fontToApply = guiFont2Local;
626 break;
627 case 3:
628 fontToApply = guiFont3Local;
629 break;
630 default:
631 fontToApply = guiFont1Local;
632 break;
633 }
634
635 if (fontToApply != null) {
636 l.setFont(fontToApply);
637 }
638 l.setMaximumSize(
639 new Dimension(Short.MAX_VALUE, (int) l.getMinimumSize().getHeight()));
640 return l;
641 }
642
643 public JTextField createJTextField(String text, boolean editable, String tooltip) {
644
645 JTextField tf = new JTextField(text, text.length() + 3);
646 tf.setEditable(editable);
647 tf.setHorizontalAlignment(JTextField.RIGHT);
648
649 if (guiFont2Local != null) {
650 tf.setFont(guiFont2Local);
651 }
652
653 tf.setMaximumSize(
654 new Dimension(Short.MAX_VALUE, (int) tf.getMinimumSize().getHeight()));
655 tf.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
656
657 tf.setToolTipText(tooltip);
658
659 return tf;
660 }

Pagina 121 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

661
662 public JToggleButton createJToggleButton(String knopTekst, String tooltip,
663 boolean reedsGeactiveerd) {
664 JToggleButton tb = new JToggleButton(knopTekst, reedsGeactiveerd);
665 tb.setToolTipText(tooltip);
666 tb.setFont(guiFont1Local);
667 return tb;
668 }
669
670 public void exportCBTHSettingsToTXT() {
671
672 FileWriter fw = null;
673 PrintWriter pw = null;
674
675 try {
676
677 String[] filepadComp = { "CBTHSettingsFile.txt" };
678 String pad = makeSysIndepFilePath(filepadComp, 2);
679 fw = new FileWriter(pad, false);
680 pw = new PrintWriter(fw);
681
682 pw.println(commentTag + "[This CBTHSettingsfile will be read by "
683 + "CubeThesis to initialize its settings. " + "User can make modifications.]");
684 pw.println();
685 pw.println(commentTag + "[Rule No 1: ][Modifications can be made, "
686 + "though not at runtime.]");
687 pw.println(commentTag + "[Rule No 2: ][All the data is to be wrapped "
688 + "in square brackets.]");
689 pw.println(commentTag + "[Rule No 3: ][ArrayTypes are additionally "
690 + "wrapped in curly brackets \"{\" & \"}\". Items are "
691 + "enumerated by comma's \",\"]");
692 pw.println(commentTag + "[Rule No 3: ][Not all possible settings "
693 + "should be listed below, if one agrees with the "
694 + "default he can simply omit that setting.]");
695 pw.println(commentTag + "[Rule No 4: ][The order in which the "
696 + "settings below are listed, doesn't matter.]");
697 pw.println(commentTag + "[Rule No 5: ][Within each record, "
698 + "(horizontal) order of tags should be respected.]");
699 pw.println(commentTag + "[Rule No 6: ][If some record isn't blanco, "
700 + "then the first tag should either be \"" + commentTag + "\" " + "or \""
701 + settingTag + "\".]");
702 pw.println(commentTag + "[Rule No 7: ][Without this file, "
703 + "CubeThesis recovers its factory settings. "
704 + "File will be auto-regenerated.]");
705 pw.println(commentTag + "[Rule No 8: ][Setting-name and -type "
706 + "are case sensitive, if they don't match an existing "
707 + "CBTHSetting, a new Setting will be created.]");
708 pw.println(commentTag + "[Structure: ][Setting][name][LabelText]"
709 + "[type][Value] \"some spaces added for readability\" " + "[Info]");
710 pw.println(commentTag + "[Available types: ][int, double, float,"
711 + " boolean, String, Font, intArray, doubleArray]");
712 pw.println();
713 pw.println();
714
715 CBTHSetting cbths = null;
716
717 for (int i = 0; i < cbthSettingsList.size(); i++) {
718 cbths = cbthSettingsList.get(i);
719 if (cbths.getEditable()) {
720 pw.print(settingTag);
721 pw.println(cbths.exportCBTHSetting());
722 }
723 }
724
725 pw.flush();
726

Pagina 122 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

727 System.out.println("CBTHSettings saved to: " + pad);


728
729 } catch (IOException ioe) {
730 System.err.println(
731 "ERROR: An IO-Exception " + "occurred during writing to the CBTHSettingsFile. "
732 + "Our apologies for the inconvenience.");
733 }
734
735 finally {
736 // Finally trying to close the streams.
737 if (pw != null) {
738 pw.close();
739 } else if (fw != null) {
740 try {
741 fw.close();
742 } catch (IOException ioe) {
743 System.err.println("ERROR: An IO-Exception occurred during "
744 + "attempt to close the FileWriter for the CBTHSettingsFile."
745 + " Our apologies for the inconvenience.");
746 }
747 }
748 }
749 }
750
751 public void filterSettingsOnTextFragment(String textFragment) {
752 cbthSettingSelection.clear();
753
754 currentSettingsFilter = textFragment;
755 // Applied filter is also stored, for use after sorting.
756
757 if (textFragment == null || textFragment.equals("")) {
758 cbthSettingSelection.addAll(cbthSettingsList);
759 } else {
760 for (CBTHSetting cbths : cbthSettingsList) {
761
762 // If specified fragment is found in CBTHSetting's name or
763 // labelText, it is added to the Secetion.
764 if (cbths.containsFragment(textFragment)) {
765 cbthSettingSelection.add(cbths);
766 }
767 }
768 }
769 // To make any visualCBTHSettingsCustomizer-Object update.
770 updateVisualCBTHSList();
771 }
772
773 public void importCBTHSettingFromLine(String line, String openingBracket,
774 String closingBracket) {
775
776 // unbrackets the line, then checks if an already existing CBTHSetting
777 // should be updated, or if a new CBTHSetting should be made.
778
779 int fromIndex = 0;
780 int endIndex = 0;
781
782 ArrayList<String> stringComponents = new ArrayList<String>();
783
784 do {
785 fromIndex = line.indexOf(openingBracket, fromIndex) + 1;
786 endIndex = line.indexOf(closingBracket, fromIndex);
787
788 if (fromIndex != -1 && endIndex != -1) {
789 stringComponents.add(line.substring(fromIndex, endIndex));
790 fromIndex = endIndex + 1;
791 }
792 } while ((endIndex < line.length() - 1 && fromIndex != -1 && endIndex != -1));

Pagina 123 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

793
794 CBTHSetting cbths = null;
795
796 if (stringComponents.size() > 2) {
797 // Three strings detected would already mean a name,
798 // a type and a value.
799 // Read setting might already exist.
800 try {
801 cbths = seekCBTHSetting(stringComponents.get(0));
802
803 if (cbths.getEditable()) {
804 if (!cbths.getType().equals(stringComponents.get(2))) {
805 throw new NoMatchingSettingTypeException(cbths.getName(),
806 stringComponents.get(2), cbths.getType());
807 }
808
809 if (stringComponents.size() > 4) {
810 cbths.setAll(null, stringComponents.get(1), null, stringComponents.get(3),
811 stringComponents.get(4));
812 } else {
813 // WorkAround to make info-tag not required from
814 // the list.
815 cbths.setAll(null, stringComponents.get(1), null, stringComponents.get(3),
816 null);
817 }
818 }
819 } catch (NoMatchingSettingTypeException nmste) {
820 System.err.println(nmste);
821 } catch (NoSuchSettingFoundException nssfe) {
822 // Read setting might be a new setting, so a new
823 // CBTHSetting will be created.
824 cbthSettingsList.add(new CBTHSetting(stringComponents.get(0),
825 stringComponents.get(1), stringComponents.get(2), stringComponents.get(3),
826 true, stringComponents.get(4)));
827 }
828 }
829 }
830
831 public void importCBTHSettingsFromTXT() {
832
833 FileReader fr = null;
834 BufferedReader br = null;
835
836 try {
837 File cbthSettingsFile = new File(
838 makeSysIndepFilePath(new String[] { "CBTHSettingsFile.txt" }, 2));
839
840 if (!cbthSettingsFile.exists()) {
841 throw new NotAvailableException("CBTHSettingsFile.txt",
842 "Default settings will be loaded.");
843 }
844
845 fr = new FileReader(cbthSettingsFile);
846 br = new BufferedReader(fr);
847
848 String readLine = "";
849
850 while ((readLine = br.readLine()) != null) {
851
852 if (readLine.startsWith(settingTag)) {
853 importCBTHSettingFromLine(
854 readLine.substring(settingTag.length(), readLine.length()), "[", "]");
855 }
856 }
857
858 } catch (IOException ioe) {

Pagina 124 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

859 System.err.println(ioe);
860 } catch (NotAvailableException nae) {
861 System.err.println(nae);
862 }
863
864 finally {
865 if (br != null) {
866 try {
867 br.close();
868 } catch (IOException ioe) {
869 System.err.println("ERROR: An IO-Exception occurred "
870 + "during attempt to close the BufferedReader "
871 + "of the CBTHSettingsFile. Our apologies for the " + "inconvenience.");
872 }
873 } else {
874 if (fr != null) {
875 try {
876 fr.close();
877 } catch (IOException ioe) {
878 System.err.println("ERROR: An IO-Exception occurred during attempt to "
879 + "close the FileReader of the CBTHSettingsFile."
880 + " Our apologies for the inconvenience.");
881 }
882 }
883 }
884 }
885 }
886
887 public String makeSysIndepFilePath(String[] pathStructure, int whatPrefix) {
888
889 StringBuffer sb = new StringBuffer();
890 String fS = getString("fileSeparator");
891
892 switch (whatPrefix) {
893 case 0:
894 ;
895 /* Nothing is added. */ break;
896 case 1:
897 sb.append(fS);
898 break;
899 case 2:
900 sb.append(getString("basicRelativePath"));
901 sb.append(fS);
902 break;
903 case 3:
904 sb.append(getCurrentProject());
905 sb.append(fS);
906 break;
907 default:
908 break;
909 }
910
911 // Adding the remaining pathstructure
912 int s;
913 for (s = 0; s < pathStructure.length - 1; s++) {
914 sb.append(pathStructure[s]);
915 sb.append(fS);
916 }
917
918 // Na het laatste item moet geen file separator meer komen, het
919 // laatste item kan immers een bestandsnaam zijn.
920 sb.append(pathStructure[s]);
921
922 return sb.toString();
923 }
924

Pagina 125 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

925 public void restoreSituationSimonAndPieter() {


926 // For automatically creating sync-ing JTextfields... from CBTHSettings
927 // below, Fonts should be created first, since they're already applied
928 // at that point.
929 setFont("guiFont1", "Century Gothic, 0, 12");
930 setFont("guiFont2", "Consolas, 0, 12");
931 setFont("guiFont3", "Stencil, 0, 12");
932 guiFont1Local = getFont("guiFont1");
933 guiFont2Local = getFont("guiFont2");
934 guiFont3Local = getFont("guiFont3");
935
936 // Set CBTHSettings, who are not editable and won't show up in the
937 // "CBTHSettingsList.txt".
938 // Settings below depend on OS-type / computer on which CubeThesis runs.
939 setString("basicRelativePath", new File("").getAbsolutePath());
940 setString("fileSeparator", "File.separator");
941 setString("fileSeparatorToText", "/FILESEPARATOR/");
942 setString("newLine", System.getProperty("line.separator"));
943
944 // Set remaining CBTHSettings, that are editable.
945 // General settings.
946 setBoolean("cbthGUITakesOSLook", true);
947 setInt("consoleRecordsMin", 250);
948 setInt("consoleRecordsMax", 500);
949 setBoolean("saveCBTHSettingsOnExit", true);
950
951 // Variables linked to the CubeReading process.
952 setString("captureDevice", "0");
953 setString("ipAddressCamera", "10.192.174.181");
954
955 setInt("xCoCrop", 668);
956 setInt("yCoCrop", 283);
957 setInt("widthCrop", 194);
958 setInt("heightCrop", 184);
959
960 setIntArray("cubeReadingToppleArray", new int[] { 3, 5, 3, 5, 3 });
961 setIntArray("cubeReadingMCFRotationArray", new int[] { 1, 1, 1, 2, 2, 0 });
962 setIntArray("cubeReadingMCFAssignArray", new int[] { 3, 2, 4, 0, 5, 1 });
963
964 // Settings that are options in the process of color recognition.
965 setBoolean("extensiveSampleOutprint", false);
966 setDouble("thresholdColorEstimation", 75.0);
967 setInt("amountOfSamplesPerFacelet", 7);
968 setInt("amountOfSampleAveraging", 3);
969
970 // Settings below are used for color recognition.
971 setInt("minBrightnessWhite", 70);
972 setInt("maxSaturationWhite", 35);
973 setInt("maxBrightnessBlack", 15);
974 setInt("distinctionRedOrange", 10);
975 setInt("distinctionOrangeYellow", 45);
976 setInt("distinctionYellowGreen", 65);
977 setInt("distinctionGreenBlue", 170);
978 setInt("distinctionBluePurple", 290);
979 setInt("distinctionPurpleRed", 330);
980
981 // Settings that concern algorithmic solving process.
982 setBoolean("updateVisualizationWithRobot", true);
983 setInt("timeToSolveAlgorithm", 15);
984 setString("ipAddressRobot", "10.129.174.171");
985 setInt("portNmbrServerSocket", 8221);
986 setInt("noValidCommand", -3);
987
988 // Exceptions that are editable, but don't need to be added to the
989 // settingsList.
990 currentProject = new CBTHSetting("currentProject", "Current project:", "String",

Pagina 126 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

991 new File(makeSysIndepFilePath(


992 new String[] { "CubeThesisProjects", "DefaultProject" }, 2))
993 .getAbsolutePath(),
994 true, "Restores the \"DefaultProject\" " + "if not available.");
995 }
996
997 public CBTHSetting seekCBTHSetting(String settingName)
998 throws NoSuchSettingFoundException {
999 CBTHSetting cbths = null;
1000
1001 boolean foundYet = false;
1002 int listIndex = 0;
1003
1004 while (listIndex < cbthSettingsList.size() && !foundYet) {
1005 cbths = cbthSettingsList.get(listIndex);
1006 if (cbths.getName().equals(settingName)) {
1007 foundYet = true;
1008 } else {
1009 listIndex++;
1010 cbths = null;
1011 }
1012 }
1013 if (cbths == null) {
1014 throw new NoSuchSettingFoundException(settingName);
1015 }
1016 return cbths;
1017 }
1018
1019 public void sortCBTHSettings(int sortMode) {
1020 switch (sortMode) {
1021 case 0:
1022 Collections.sort(cbthSettingsList, new IdCBTHSettingComparator());
1023 break;
1024 case 1:
1025 Collections.sort(cbthSettingsList, new LabelTextCBTHSettingComparator());
1026 break;
1027 case 2:
1028 Collections.sort(cbthSettingsList, new TypeCBTHSettingComparator());
1029 break;
1030 default:
1031 break;
1032 }
1033 // After sorting, the visual setting's representation will be
1034 // updated with the most recent filter:
1035 filterSettingsOnTextFragment(currentSettingsFilter);
1036 }
1037
1038 public static ArrayList<String> splitStringByCommas(String text, int offsetBegin,
1039 int offsetEnd) {
1040
1041 int fromIndex = offsetBegin;
1042 int endIndex = 0;
1043
1044 ArrayList<String> stringComponents = new ArrayList<String>();
1045
1046 while (endIndex < text.length() - offsetEnd) {
1047
1048 endIndex = text.indexOf(",", fromIndex);
1049
1050 if (endIndex == -1) {
1051 endIndex = text.length() - offsetEnd;
1052 }
1053 stringComponents.add(omitSpaces(text.substring(fromIndex, endIndex)));
1054 fromIndex = endIndex + 1;
1055 }
1056 return stringComponents;

Pagina 127 van 329 CubeThesis™ Depamelaere-Deschuytter


class CBTHSettingsList

1057 }
1058
1059 public String translateColorsIntToString(int k) {
1060
1061 if (k > -1 && k < 7) {
1062 return CUBECOLORS[k];
1063 } else {
1064 return CUBECOLORS[6];
1065 }
1066 }
1067
1068 public int translateColorsStringToInt(String str) {
1069
1070 switch (str) {
1071 case COLORRED:
1072 return 0;
1073 case COLORBLUE:
1074 return 1;
1075 case COLORYELLOW:
1076 return 2;
1077 case COLORORANGE:
1078 return 3;
1079 case COLORGREEN:
1080 return 4;
1081 case COLORWHITE:
1082 return 5;
1083 default:
1084 return 6;
1085 }
1086 }
1087
1088 /**
1089 * This method is part of the Observer-Observable technique. It will trigger
1090 * its Observers.
1091 */
1092 public void updateVisualCBTHSList() {
1093 setChanged();
1094 notifyObservers();
1095 }
1096
1097 // Static method:
1098 public static String omitSpaces(String text) {
1099
1100 String trimmed = text;
1101
1102 // Omit the spaces at the start.
1103 while (trimmed.startsWith(" ")) {
1104 trimmed = trimmed.substring(1, trimmed.length());
1105 }
1106
1107 // Omit the spaces at the end.
1108 while (trimmed.endsWith(" ")) {
1109 trimmed = trimmed.substring(0, trimmed.length() - 1);
1110 }
1111 return trimmed;
1112 }
1113 }

Pagina 128 van 329 CubeThesis™ Depamelaere-Deschuytter


class ColorEstimation

1 package model;
2
3 import java.awt.Color;
4 import java.awt.image.BufferedImage;
5 import java.util.Random;
6
7 import javax.swing.ImageIcon;
8 import javax.swing.JLabel;
9 import javax.swing.JOptionPane;
10
11 public class ColorEstimation {
12
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14 private static BufferedImage[][] cells;
15 private static Random rand;
16
17 private static int minBrightWhite;
18 private static int maxSaturWhite;
19 private static int maxBrightBlack;
20 private static int distinctionRedOrange;
21 private static int distinctionOrangeYellow;
22 private static int distinctionYellowGreen;
23 private static int distinctionGreenBlue;
24 private static int distinctionBluePurple;
25 private static int distinctionPurpleRed;
26
27 private static boolean extensiveSampleOutprint;
28 private static int amountOfSamplesPerFacelet;
29 private static int amountOfSampleAveraging;
30
31 // Static methods:
32 public static CubeFace colorRecognition(CBTHImage currentCBTHImage) {
33
34 CubeFace cubeFace = null;
35 cells = new BufferedImage[3][3];
36 rand = new Random();
37
38 extensiveSampleOutprint = cbthsl.getBoolean("extensiveSampleOutprint");
39 amountOfSamplesPerFacelet = cbthsl.getInt("amountOfSamplesPerFacelet");
40 amountOfSampleAveraging = cbthsl.getInt("amountOfSampleAveraging");
41
42 BufferedImage cropped = currentCBTHImage.getImgCropped();
43
44 /*
45 * Color-data is retrieved once at the beginning of the procedure and reused
46 * for every facelet of the face.
47 */
48 minBrightWhite = cbthsl.getInt("minBrightnessWhite");
49 maxSaturWhite = cbthsl.getInt("maxSaturationWhite");
50 maxBrightBlack = cbthsl.getInt("maxBrightnessBlack");
51 distinctionRedOrange = cbthsl.getInt("distinctionRedOrange");
52 distinctionOrangeYellow = cbthsl.getInt("distinctionOrangeYellow");
53 distinctionYellowGreen = cbthsl.getInt("distinctionYellowGreen");
54 distinctionGreenBlue = cbthsl.getInt("distinctionGreenBlue");
55 distinctionBluePurple = cbthsl.getInt("distinctionBluePurple");
56 distinctionPurpleRed = cbthsl.getInt("distinctionPurpleRed");
57
58 int cropheightparam = cropped.getHeight() / 3,
59 cropwidthparam = cropped.getWidth() / 3,
60 averageHalfWidthFacelet = (cropwidthparam) / 2,
61 averageHalfHeightFacelet = (cropheightparam) / 2, centerPointX = 0,
62 centerPointY = 0;
63 double factor = .65;
64 int rgb = 0;
65 String str1 = null, str2 = null, str3 = null;
66

Pagina 129 van 329 CubeThesis™ Depamelaere-Deschuytter


class ColorEstimation

67 // Preparing ingredients for a CubeFace:


68 int[][] colorsMatrix = new int[3][3];
69 double[][] confidenceMatrix = new double[3][3];
70
71 // Row by row ('j'), the facelets are treated from left to right ('l').
72 for (int j = 0; j < cells.length; j++) {
73 for (int l = 0; l < cells[0].length; l++) {
74 rgb = 0;
75 System.out.println("*******************************************");
76 System.out.println("CBTHImage \"" + currentCBTHImage + "\" : "
77 + "color-estimation facelet (row, column): " + j + ", " + l);
78 centerPointX = averageHalfWidthFacelet + l * cropwidthparam;
79 centerPointY = averageHalfHeightFacelet + j * cropheightparam;
80
81 // Store subimages in "cells"-array:
82 cells[j][l] = cropped.getSubimage(
83 (int) (centerPointX - averageHalfWidthFacelet * factor),
84 (int) (centerPointY - averageHalfHeightFacelet * factor),
85 (int) (cropwidthparam * factor), (int) (cropheightparam * factor));
86
87 // Uncomment line below to show the sub-images.
88 // JOptionPane.showMessageDialog(null,
89 // new JLabel(new ImageIcon(cells[j][l])));
90
91 // Preparing more variables;
92 int pixelpickerX = 0, pixelpickerY = 0;
93 int colorSamples[] = new int[amountOfSamplesPerFacelet];
94 int color = 6;
95
96 if (extensiveSampleOutprint) {
97 System.out.println(" ------------------");
98 }
99
100 // The process in the loop is done for each (main)sample:
101 for (int m = 0; m < amountOfSamplesPerFacelet; m++) {
102
103 if (extensiveSampleOutprint) {
104 str1 = " - MAINSAMPLE " + (m + 1);
105 System.out.print(str1 + numberOfSpaces(str1, 20));
106 }
107
108 int[][] rgbData = new int[amountOfSampleAveraging][];
109
110 /*
111 * For each sub-sample: a random pixel is picked, and its rgb-data is
112 * stored in the array with the same name.
113 */
114 for (int n = 0; n < rgbData.length; n++) {
115 do {
116 pixelpickerX = (int) Math.round(rand.nextDouble() * cells[j][l].getWidth());
117 } while (pixelpickerX >= cells[j][l].getWidth());
118
119 do {
120 pixelpickerY = (int) Math
121 .round(rand.nextDouble() * cells[j][l].getHeight());
122 } while (pixelpickerY >= cells[j][l].getHeight());
123
124 rgb = cells[j][l].getRGB(pixelpickerX, pixelpickerY);
125 rgbData[n] = getRGBSeparated(rgb);
126 /*
127 * NOTE: The subsamples don't need to be converted individually to
128 * HSB-values, this effort can be saved since the converting the
129 * averaged sample to HSB- values, will yield for the same results.
130 */
131 }
132

Pagina 130 van 329 CubeThesis™ Depamelaere-Deschuytter


class ColorEstimation

133 // The Red, (resp. Green, Blue) values are averaged:


134 int[] rgbDataAveraged = averageRGBData(rgbData);
135
136 // Color is determined, and saved in the colorSamples-array:
137 color = whatColorIsPixel(rgbDataAveraged[0], rgbDataAveraged[1],
138 rgbDataAveraged[2]);
139 colorSamples[m] = color;
140
141 if (extensiveSampleOutprint) {
142 str2 = "X-co: " + pixelpickerX;
143 // Print the location of the latest sub-sample taken.
144 str3 = "Y-co: " + pixelpickerY;
145 System.out
146 .print(str2 + numberOfSpaces(str2, 12) + str3 + numberOfSpaces(str3, 11));
147 System.out
148 .println("Color [" + cbthsl.translateColorsIntToString(color) + "]");
149 }
150 }
151
152 if (extensiveSampleOutprint) {
153 System.out.println(" ------------------");
154 }
155
156 // Count frequency of detection of each color for a given
157 // colorSamples-array:
158 int[] hist = histogramAnalysis(colorSamples);
159 color = determineMostFrequentSample(hist);
160 colorsMatrix[j][l] = color;
161
162 // The confidenceLevel takes only the mainSamples into account!
163 // "100d" specifies number of digits.
164 double confidenceLevel = Math
165 .round((100 * (hist[color] + 0.0) / colorSamples.length) * 100d) / 100d;
166 // If the obtained color is "None", then the confidence is
167 // set to be 0.0.
168 confidenceMatrix[j][l] = color == 6 ? 0.0 : confidenceLevel;
169
170 String colorEstimation = cbthsl.translateColorsIntToString(color);
171 System.out
172 .println("COLORESTIMATION: [" + colorEstimation + "] Confidence-level: ["
173 + confidenceLevel + "%] These are the " + amountOfSamplesPerFacelet
174 + " sample(s) listed: " + arrayPrint(colorSamples));
175 }
176 }
177 System.out.println("*******************************************");
178
179 // Create CubeFace from the extracted data:
180 cubeFace = new CubeFace(null, colorsMatrix, confidenceMatrix);
181 return cubeFace;
182 }
183
184 // Auxiliary static methods (alphabetically):
185 public static String arrayPrint(int[] array) {
186
187 StringBuffer sb = new StringBuffer();
188 sb.append("[");
189
190 for (int i = 0; i < array.length - 1; i++) {
191 sb.append(cbthsl.translateColorsIntToString(array[i]) + ", ");
192 }
193 sb.append(cbthsl.translateColorsIntToString(array[array.length - 1]) + "]");
194
195 return sb.toString();
196 }
197
198 /**

Pagina 131 van 329 CubeThesis™ Depamelaere-Deschuytter


class ColorEstimation

199 * Averages channel by channel the data.


200 *
201 * @param rgbData
202 * Input of type int[][]
203 * @return int[] with averaged data per channel.
204 */
205 public static int[] averageRGBData(int[][] rgbData) {
206
207 int[] rgbDataAveraged = new int[3];
208
209 for (int i = 0; i < rgbData[0].length; i++) {
210 // Sum all numbers in rgbDataAveraged' cells color by color:
211 for (int j = 0; j < rgbData.length; j++) {
212 rgbDataAveraged[i] += rgbData[j][i];
213 }
214 rgbDataAveraged[i] /= rgbData.length;
215 }
216 return rgbDataAveraged;
217 }
218
219 /**
220 * Determines which color (=index) was most frequently detected.
221 *
222 * @param hist
223 * Array containing the frequency for each of 7 colors for a certain
224 * facelet. (Also "None")
225 * @return The color (int value) that wast most popular.
226 */
227 public static int determineMostFrequentSample(int[] hist) {
228
229 int mostFreqIndex = -1, occurrence = 0;
230 for (int t = 0; t < hist.length; t++) {
231 if (occurrence < hist[t]) {
232 mostFreqIndex = t;
233 occurrence = hist[t];
234 }
235 }
236 /*
237 * If an ex aequo occurs between two colors, the color with the smallest
238 * index is privileged, so more likely to be accepted.
239 */
240 return mostFreqIndex;
241 }
242
243 /**
244 * Unpacks rgb data to 3 int-numbers, one for each channel.
245 *
246 * @param rgb
247 * The RGB-data from a pixel is inputted.
248 * @return An array is returned with the RGB data separated.
249 */
250 public static int[] getRGBSeparated(int rgb) {
251 // Source: http://stackoverflow.com/questions/22178978/
252 // java-colour-detection
253 // Source: Applet using same color-scale: http://hslpicker.com/#bd7575
254
255 int[] rgbArray = new int[3];
256
257 /*
258 * Color in different programming languages is usually represented by a red,
259 * green and blue component. The final color is a combination of the three
260 * primary colors of light. Typically, values are used ranging from 0 to 255
261 * for each of the components, however, some systems will want you to enter
262 * a hexadecimal number in the form RRGGBB where RR is the red value
263 * expressed as hexadecimal, GG is the green value, and BB is the blue
264 * value. Other systems, such as Java, will want an integer where bits 0-7

Pagina 132 van 329 CubeThesis™ Depamelaere-Deschuytter


class ColorEstimation

265 * are the blue value, 8-15 the green, and 16-23 the red, so each color
266 * occupies 8 bits. A .png imageformat supports an alpha channel, these bits
267 * occupy the bits 24-31.
268 *
269 * In what follows the last hexadecimal number (0xFF) represents 255; '&' =
270 * bitwise operation that retains the bits that occur at the same locations
271 * in both numbers; '>>' means the bits are shifted to the right with the
272 * specified amount places.
273 */
274
275 rgbArray[0] = (rgb >> 16) & 0xFF;// RED Channel: 16 places shifting.
276 rgbArray[1] = (rgb >> 8) & 0xFF;// Green Channel: 8 places shifting.
277 rgbArray[2] = (rgb) & 0xFF;// Blue Channel: no shifting.
278
279 /*
280 * NOTE: Calculating an average of 'packed' rgb-numbers is pointless. And:
281 * Some colors have more appearances: int rgb=-98830 & int rgb= 16678386
282 * yield for color R=254, G=125, B=242.
283 */
284
285 return rgbArray;
286 }
287
288 /**
289 * Counts the frequency of each color in the colorSamplesArray.
290 *
291 * @param colorSamplesArray
292 * input by means of a int[].
293 * @return An int[7] is returned, with the frequencies.
294 */
295 public static int[] histogramAnalysis(int[] colorSamplesArray) {
296
297 int[] hist = new int[7];
298 /* The array has a field for each color, including "None"-color. */
299
300 for (int j = 0; j < colorSamplesArray.length; j++) {
301 hist[colorSamplesArray[j]]++;
302 }
303 return hist;
304 }
305
306 /**
307 * Less important method: fakes a 'tab' mechanism by adding spaces instead of
308 * tabs. The advantage is: output is displayed in the same way in the console/
309 * notepad.
310 */
311 public static String numberOfSpaces(String str, int ref) {
312
313 StringBuffer sb = new StringBuffer(" "); // Add minimum 1x space.
314
315 for (int i = 0; i < (ref - str.length()); i++) {
316 sb.append(" ");
317 }
318 return sb.toString();
319 }
320
321 /**
322 * Will determine the color of a pixel given rgb-data.
323 *
324 * @param rRGB
325 * the red channel.
326 * @param gRGB
327 * the green channel.
328 * @param bRGB
329 * the blue channel.
330 * @return A int number representing the obtainded color.

Pagina 133 van 329 CubeThesis™ Depamelaere-Deschuytter


class ColorEstimation

331 */
332 public static int whatColorIsPixel(int rRGB, int gRGB, int bRGB) {
333
334 // Red, Green, Blue - channels => Hue, Saturation, Brightness - channels:
335 int colorSample = 6; // 6 = "None"-color.
336 float hsb[] = new float[3];
337 Color.RGBtoHSB(rRGB, gRGB, bRGB, hsb);
338
339 // The results are rescaled slightly:
340 hsb[0] *= 360;
341 hsb[1] *= 100;
342 hsb[2] *= 100;
343
344 if (extensiveSampleOutprint) {
345 String str4 = "[R,G,B]-value: [" + rRGB + ", " + gRGB + ", " + bRGB + "]";
346 System.out.print(str4 + numberOfSpaces(str4, 33));
347 String str5 = " = [H,S,B]-value: [" + Math.round(hsb[0]) + ", " + Math.round(hsb[1])
348 + ", " + Math.round(hsb[2]) + "]";
349 System.out.print(str5 + numberOfSpaces(str5, 34));
350 }
351
352 // Nested if(){}else{}-clauses to determine the color:
353
354 // First White and black are intercepted:
355 if (hsb[1] < maxSaturWhite && hsb[2] > minBrightWhite)
356 colorSample = 5;
357 else {
358 if (hsb[2] < maxBrightBlack)
359 colorSample = 6;
360 else {
361 float hue = hsb[0];
362
363 /*
364 * A bunch of nested if-else clauses is preferably avoided in Java, a no
365 * further elaborated alternative would be to work with a NavigableMap.
366 * It yields for the same functionality, only slightly more elegant.
367 * Another alternative would be to organize the 360 range as a 'tree',
368 * and than gradually descend to the colors lying within range.
369 */
370
371 // sample = Red
372 if (hue >= 0 && hue < distinctionRedOrange)
373 colorSample = 0;
374 // sample = Orange
375 else if (hue >= distinctionRedOrange && hue < distinctionOrangeYellow)
376 colorSample = 3;
377 // sample = Yellow
378 else if (hue >= distinctionOrangeYellow && hue < distinctionYellowGreen)
379 colorSample = 2;
380 // sample = Green
381 else if (hue >= distinctionYellowGreen && hue < distinctionGreenBlue)
382 colorSample = 4;
383 // sample = Blue
384 else if (hue >= distinctionGreenBlue && hue < distinctionBluePurple)
385 colorSample = 1;
386 // sample = None +- purple
387 else if (hue >= distinctionBluePurple && hue < distinctionPurpleRed)
388 colorSample = 6;
389 // sample = Red
390 else
391 colorSample = 0;
392
393 /*
394 * NOTE: Instead of checking for White/Black first, a alternative using
395 * more parameters and therefore a more advanced solution could use
396 * bounds for white/black for each color. The distinction between yellow

Pagina 134 van 329 CubeThesis™ Depamelaere-Deschuytter


class ColorEstimation

397 * and white, could be more sensitive than blue-white.


398 */
399 }
400 }
401 return colorSample;
402 }
403 }

Pagina 135 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

1 package model;
2
3 import java.io.*;
4 import java.util.*;
5
6 import solver.solverJS.viewSolverJS.Cubie;
7
8 public class CommandSeq {
9
10 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
11 private static int[] cubieSolMoves = null;
12 private static int[] cubieSolAmount = null;
13 private static int cubieSolLen = 0;
14 private static int[][] solutionCommandsMatrix = null;
15 private static int robotPositionHor = 0;
16 private static int robotPositionVer = 0;
17 // This is the "queue", a FIFO-system of handling the moves.
18 private volatile static Queue<Integer> commandQueue = new LinkedList<Integer>();
19
20 // Getters:
21 /**
22 * This method is for use within this class. It is also called to determine
23 * whether is time to update Cubie's visualization.
24 *
25 * @param syncingWithRobotPurpose
26 * boolean specifying the goal of calling this method.
27 */
28 public static int getNextMove(boolean syncingWithRobotPurpose) {
29 int command = cbthsl.getInt("noValidCommand");
30
31 if (solutionCommandsMatrix != null) {
32 if (robotPositionHor < solutionCommandsMatrix.length) {
33
34 command = solutionCommandsMatrix[robotPositionHor][robotPositionVer];
35
36 if (robotPositionVer + 1 < solutionCommandsMatrix[robotPositionHor].length) {
37 robotPositionVer++;
38 } else {
39
40 if (robotPositionHor < solutionCommandsMatrix.length) {
41 robotPositionHor++;
42 robotPositionVer = 0;
43 /*
44 * System.out.println("A new 'packed' move was performed"); At this
45 * point Cubie's visualization needs an update. '0' is returned in
46 * that case.
47 */
48
49 if (syncingWithRobotPurpose) {
50 command = 0;
51 }
52 }
53 }
54 }
55 }
56 return command;
57 }
58
59 public static int getQueueSize() {
60 return commandQueue.size();
61 }
62
63 /**
64 * Gets the robot's position in the 2-dim solutionCommandsMatrix. Horizontal,
65 * means the first index.
66 */

Pagina 136 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

67 public static int getRobotPositionHor() {


68 return robotPositionHor;
69 }
70
71 /**
72 * Gets the robot's position in the 2-dim solutionCommandsMatrix. Vertical,
73 * means the second index.
74 */
75 public static int getRobotPositionVer() {
76 return robotPositionVer;
77 }
78
79 // Setters:
80 public static void setRobotPositionHor(int posHor) {
81 robotPositionHor = posHor;
82 }
83
84 public static void setRobotPositionVer(int posVer) {
85 robotPositionVer = posVer;
86 }
87
88 /**
89 * Transition from the "MoveSequenceToRobotListener" to this Class CommandSeq.
90 *
91 * @param moves
92 * @param amount
93 * @param len
94 */
95 public static void setSolutionCommandsMatrix(int[] moves, int[] amount, int len) {
96 cubieSolMoves = moves;
97 cubieSolAmount = amount;
98 cubieSolLen = len;
99 solutionCommandsMatrix = translateMoves(moves, amount, len);
100 exportCommandsAsTXT();
101 }
102
103 // Static methods:
104 /**
105 * Adds a new command to the robot's queue.
106 *
107 * @param command
108 * The number/command one wants to add.
109 */
110 public static void addNewCommand(int command) {
111
112 if (command != cbthsl.getInt("noValidCommand")) {
113 commandQueue.add(new Integer(command));
114 System.out.println("Command \"" + command + "\" was added to the "
115 + "commandQueue of the robot succesfully.");
116 }
117 }
118
119 /**
120 * Reads a binary array.
121 *
122 * @param dis
123 * The DataInputStreamobject to the SaveFile.
124 * @return An int[]-array is returned.
125 * @throws IOException
126 */
127 public static int[] arrayFromSaveFile(DataInputStream dis) throws IOException {
128
129 int arrayLength = dis.readInt();
130 int[] arrayToReturn = new int[arrayLength];
131
132 for (int index = 0; index < arrayToReturn.length; index++) {

Pagina 137 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

133 arrayToReturn[index] = dis.readInt();


134 }
135 return arrayToReturn;
136 }
137
138 /**
139 * Saves an int[]-array to a binary SaveFile.
140 *
141 * @param dos
142 * The DataOutputStreamobject to the SaveFile.
143 * @param array
144 * The array that needs to be saved.
145 * @throws IOException
146 */
147 public static void arrayToSaveFile(DataOutputStream dos, int[] array)
148 throws IOException {
149 dos.writeInt(array.length);
150 for (int index = 0; index < array.length; index++) {
151 dos.writeInt(array[index]);
152 }
153 }
154
155 /**
156 * Encodes the move according to the agreement with the robot software.
157 *
158 * @param m
159 * move-number.
160 * @return 2^m int-number.
161 */
162 public static int codeMove(int m) {
163 return (int) Math.pow(2, m);
164 }
165
166 /**
167 * Reads cube-solution related data from the SaveFile.
168 *
169 * @param dis
170 * The DataInputStreamobject from the SaveFile.
171 * @throws IOException
172 */
173 public static void commandSeqFromSaveFile(DataInputStream dis) throws IOException {
174 // Original data from Cubie:
175 cubieSolMoves = arrayFromSaveFile(dis);
176 cubieSolAmount = arrayFromSaveFile(dis);
177 cubieSolLen = dis.readInt();
178
179 // Data kept in CubeThesis:
180 robotPositionHor = dis.readInt();
181 robotPositionVer = dis.readInt();
182
183 int lenOfSolComMatrix = dis.readInt();
184 solutionCommandsMatrix = new int[lenOfSolComMatrix][];
185 for (int index = 0; index < solutionCommandsMatrix.length; index++) {
186 solutionCommandsMatrix[index] = arrayFromSaveFile(dis);
187 }
188
189 // Update Cubie:
190 Cubie cubie = CommonObjects.getCubie();
191 cubie.cubieSetMoveSeq(cubieSolMoves, cubieSolAmount, cubieSolLen, robotPositionHor);
192 }
193
194 /**
195 * Saves cube-solution related data to the SaveFile.
196 *
197 * @param dos
198 * The DataOutputStreamobject to the SaveFile.

Pagina 138 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

199 * @throws IOException


200 */
201 public static void commandSeqToSaveFile(DataOutputStream dos) throws IOException {
202
203 // Original data from Cubie:
204 arrayToSaveFile(dos, cubieSolMoves);
205 arrayToSaveFile(dos, cubieSolAmount);
206 dos.writeInt(cubieSolLen);
207
208 // Data kept in CubeThesis:
209 dos.writeInt(robotPositionHor);
210 dos.writeInt(robotPositionVer);
211
212 dos.writeInt(solutionCommandsMatrix.length);
213 for (int index = 0; index < solutionCommandsMatrix.length; index++) {
214 arrayToSaveFile(dos, solutionCommandsMatrix[index]);
215 }
216 }
217
218 /**
219 * Checks whether data kept in Class CommandSeq is worth saving.
220 *
221 * @return A boolean is returned. true = it's worth saving.
222 */
223 public static boolean commandSeqWorthSaving() {
224 boolean worthSaving = false;
225
226 if (cubieSolMoves != null || cubieSolAmount != null
227 || solutionCommandsMatrix != null) {
228 worthSaving = true;
229 }
230
231 return worthSaving;
232 }
233
234 /** Exports the commands to a textFile in the currentProject. */
235 public static void exportCommandsAsTXT() {
236
237 FileWriter fw = null;
238 PrintWriter pw = null;
239
240 try {
241
242 String[] pathComponents = { "SolvingCommands.txt" };
243 String path = cbthsl.makeSysIndepFilePath(pathComponents, 3);
244 fw = new FileWriter(path, false);
245 pw = new PrintWriter(fw);
246
247 pw.print(solutionCommandsMatrixToString());
248 pw.flush();
249
250 System.out.println("Solution-command's are succesfully saved to: " + path);
251
252 } catch (IOException ioe) {
253 System.err.println("ERROR: An IO-Exception "
254 + "occurred during writing to the Commands-file. Our apologies "
255 + "for the inconvenience.");
256 }
257
258 finally {
259 // Finally trying to close the streams.
260 if (pw != null) {
261 pw.close();
262 } else if (fw != null) {
263 try {
264 fw.close();

Pagina 139 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

265 } catch (IOException ioe) {


266 System.err.println("ERROR: An IO-Exception occurred during attempt "
267 + "to close the FileWriter for the Commands-file. Our apologies "
268 + "for the inconvenience.");
269 }
270 }
271 }
272 }
273
274 /**
275 * The peek instruction only asks for the first command in the queue, without
276 * removing it.
277 *
278 * @return A command, int-number is returned.
279 */
280 public static int peekCommand() {
281
282 Integer command;
283 if ((command = commandQueue.peek()) != null) {
284 return command.intValue();
285 } else {
286 return cbthsl.getInt("noValidCommand");
287 }
288 }
289
290 /**
291 * Polling returns the first command in the queue, with removing it from the
292 * queue. At this point the visualization is updated if the command concerned
293 * a real cube move.
294 *
295 * @return A command, int-number is returned.
296 */
297 public static int pollCommand() {
298
299 Integer command;
300 if ((command = commandQueue.poll()) != null) {
301
302 // If "updateVisualizationWithRobot", the visualization is updated:
303 if (cbthsl.getBoolean("updateVisualizationWithRobot") && command != 0
304 && command != 3 && command != 5 && command != 7) {
305 if (getNextMove(true) == 0) {
306 /*
307 * Strange enough, we step backwards through the solution to keep up
308 * with the robot. This is because the solution received from Cubie is
309 * inverted. (from solved state-> situation).
310 */
311 CommonObjects.getCubie().stepBackward();
312 }
313 }
314 return command.intValue();
315 } else {
316 return cbthsl.getInt("noValidCommand");
317 }
318 }
319
320 /**
321 * If the a connection with the robot was established at this point, the robot
322 * will execute the moves. In this method the translated solution is added to
323 * the robot's queue.
324 */
325 public static void solutionCommandsMatrixToQueue() {
326
327 if (solutionCommandsMatrix != null) {
328 for (int i = 0; i < solutionCommandsMatrix.length; i++) {
329 for (int j = 0; j < solutionCommandsMatrix[i].length; j++) {
330 addNewCommand(solutionCommandsMatrix[i][j]);

Pagina 140 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

331 }
332 }
333 }
334 }
335
336 /** Will turn the moves to perform to a String. */
337 public static String solutionCommandsMatrixToString() {
338
339 String newLine = cbthsl.getString("newLine");
340 StringBuffer sb = new StringBuffer();
341
342 // Create a header:
343 String header = "COMMANDS CUBE-SOLUTION PROJECT "
344 + cbthsl.getCurrentProject().getName();
345
346 sb.append(header + newLine);
347
348 String lineEqualSign = "=";
349 for (int b = 0; b < header.length() - 1; b++) {
350 lineEqualSign += "=";
351 }
352
353 sb.append(lineEqualSign + newLine + newLine);
354
355 // Temporarily copy the actual robot position:
356 int tmpRobPosHor = robotPositionHor;
357 int tmpRobPosVer = robotPositionVer;
358
359 robotPositionHor = 0;
360 robotPositionVer = 0;
361
362 int counter = 0, noValidCommand = cbthsl.getInt("noValidCommand");
363 int move = getNextMove(false);
364 while (move != noValidCommand) {
365 if (move != 0) {
366 sb.append((counter + 1) + ":\t\t");
367 sb.append(move + newLine);
368 counter++;
369 }
370 move = getNextMove(false);
371 }
372
373 robotPositionHor = tmpRobPosHor;
374 robotPositionVer = tmpRobPosVer;
375
376 // Afsluiting.
377 sb.append(newLine);
378 sb.append(lineEqualSign + newLine);
379
380 return sb.toString();
381 }
382
383 /**
384 * The current queue is emptied at once, this is the fastest way to stop the
385 * robot move from the Java side: It will complete its last instruction.
386 */
387 public static void stopAsQuicklyAsPossile() {
388 commandQueue = new LinkedList<Integer>();
389 }
390
391 /**
392 * At the end of the queue, the robot will move aside and exit its program.
393 */
394 public static void terminateRobotProgram() {
395 addNewCommand(0);
396 }

Pagina 141 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

397
398 /**
399 * The movesequence, returning from "Cubie", is arranged from solved state to
400 * the problem-situation. (Rather a generating than a solving sequence) The
401 * logic in this method will invert the sequence and translate the solution to
402 * mere quarter- and half-turns (instead of (anti)-slicemoves).
403 */
404 public static int[][] translateMoves(int[] moves, int[] amount, int len) {
405
406 int[][] tempCommandMatrix = null;
407
408 if (moves != null && amount != null && len > 0) {
409
410 /*
411 * The length of the solution "len" sometimes differs from the actual
412 * length of the moves/amount array. In other words: for some reason, some
413 * solvers add additional moves to the solution, which have nothing to do
414 * with the solving sequence. So the solving part of the solution
415 * stretches "len"-amount of fields. Each move is saved at an index in the
416 * moves-array and the amount[index] states whether the move is required
417 * normal, inverted or double.
418 */
419 int tempCommand = 0;
420
421 int q = 0;
422 int m = -1;
423 tempCommandMatrix = new int[len][];
424
425 /*
426 * m=0-5, normal turn m=6-8, middle layer turn m=9-11, cube turn m=12-14,
427 * slice move (2 opposing faces turn) m=15-17, anti-slice move (variant: 2
428 * opposing faces turn)
429 *
430 * These are the numbers that can be found in the moves-array. The goal is
431 * to translate all this moves to robot-commands: quarter- & half-turns
432 * are supported. These moves are stored in a 2-dim tempCommandMatrix. The
433 * first matrixdimension is as long as "len". For each 'packed' move from
434 * the solver, an array is provided, by means of the second dimension that
435 * mentions the translated move(s).
436 *
437 * The importance of preserving the link back to the packed
438 * (non-translated moves) by putting up a 2-dim. matrix instead of a 1-dim
439 * array (with all the translated moves sequenced), is for feedback
440 * purposes. Cubie's visualization only needs its update after a packed
441 * move, not after a 'sub'-move from the robot.
442 */
443
444 for (int index = 0; index < len; index++) {
445
446 /*
447 * [len-index-1] will loop through the solution from situation to solved
448 * state: q==3: inverted move q==2: double move
449 *
450 * The code-system agreed with the robot takes 2 to the power of the
451 * face that needs rotation. Adding a negative sign will result in a
452 * counterclockwise-turn of that particular face. If it concerns a
453 * double move, then the obtained number is multiplied with 10.
454 */
455
456 q = 4 - amount[len - index - 1];
457 m = moves[len - index - 1];
458
459 if (m < 6) {
460 tempCommand = codeMove(m);
461 if (q != 2) {
462 // It concerns a quarter-move:

Pagina 142 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

463 tempCommandMatrix[index] = new int[1];


464 tempCommandMatrix[index][0] = q == 3 ? -tempCommand : tempCommand;
465 } else {
466 // It concerns a half-move:
467 tempCommandMatrix[index] = new int[1];
468 tempCommandMatrix[index][0] = tempCommand * 10;
469 }
470
471 } else {
472
473 tempCommandMatrix[index] = new int[2];
474 /*
475 * Here an extension can be elaborated: An "L slice-move" equals an
476 * "R' slice-move" and maybe this change could cancel out a
477 * pre/post-ceding, inverted command.
478 */
479
480 int a = m % 3;
481 int b = a + 3; // Symbool voor de draaibeweging aan de overkant.
482 // L->R, U->D, F->B
483 int c = m / 3; // Gaat van 2 tt 5.
484 int hulpMove1 = codeMove(a);
485 int hulpMove2 = codeMove(b);
486
487 int r = q == 3 ? -1 : 1;
488
489 switch (c) {
490 case 2:
491 /* middle layer turn komt neer op een slice move */ tempCommandMatrix[index][0] = r
492 * hulpMove1;
493 tempCommandMatrix[index][1] = -r * hulpMove2;
494 break;
495 case 3: /* cube turn */
496 System.err.println("ERROR: Unsupported cubeturn "
497 + "detected in algorithmic software, solution won't "
498 + "be correct!! Class CommandSeq will offer more " + "information.");
499 /*
500 * Hier waarschijnlijk iets beginnen met te wissen rijen uit
501 * resultaat want het kantelen heeft hier geen zin.
502 */
503 break;
504 case 4: /* slice move */
505 tempCommandMatrix[index][0] = r * hulpMove1;
506 tempCommandMatrix[index][1] = -r * hulpMove2;
507 break;
508 case 5: /* anti-slice move */
509 tempCommandMatrix[index][0] = r * hulpMove1;
510 tempCommandMatrix[index][1] = r * hulpMove2;
511 break;
512 }
513
514 if (q == 2) {
515 tempCommandMatrix[index][0] = Math.abs(10 * tempCommandMatrix[index][0]);
516 tempCommandMatrix[index][1] = Math.abs(10 * tempCommandMatrix[index][1]);
517 }
518 }
519 /*
520 * At this point, it would be possible the check whether no e.g. F and
521 * F'-commands succeed each other. This can easily been done by adding
522 * to 'adjacent' numbers.
523 *
524 * This could be made even smarter: The program seeks for o perations on
525 * opposing faces, these operations can be swapped in sequence without
526 * problems, and could maybe lead to further canceling with
527 * pre/post-ceding moves!
528 */

Pagina 143 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommandSeq

529 }
530 }
531 return tempCommandMatrix;
532 }
533 }

Pagina 144 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommonObjects

1 package model;
2
3 import java.awt.BorderLayout;
4
5 import listeners.cam.T_CAM_LiveStreamItemListener;
6 import connection.conWithRobot.CommunicationRobotThread;
7 import solver.solverJS.viewSolverJS.Cubie;
8 import listeners.solv.B_SOLV_CubeToSolverListener;
9 import listeners.solv.B_SOLV_MoveSeqToRobotListener;
10
11 /**
12 * The request for a class like this arised when developing the automatic mode.
13 * Both manual and automatic mode needed to dispose of certain common objects.
14 * This class is mere a gathering, collection of such common objects. This
15 * workaround is probably not a very clean solution.
16 */
17 public class CommonObjects {
18
19 private static CBTHSettingsList cbthsl;
20
21 private static CommunicationRobotThread commRobot;
22 private static T_CAM_LiveStreamItemListener camLSIL;
23 private static Cubie cubie;
24 private static B_SOLV_CubeToSolverListener cubeToSolver;
25 private static B_SOLV_MoveSeqToRobotListener moveSeqToRobot;
26
27 // Constructor:
28 public CommonObjects(CBTHSettingsList cbthsl) {
29
30 // Assign already created object:
31 CommonObjects.cbthsl = cbthsl;
32
33 // Create other common objects, however order of creation is important:
34 camLSIL = null;
35 commRobot = new CommunicationRobotThread();
36 cubie = new Cubie(new BorderLayout(), cbthsl);
37 cubeToSolver = new B_SOLV_CubeToSolverListener(cubie);
38 moveSeqToRobot = new B_SOLV_MoveSeqToRobotListener(cubie);
39 }
40
41 // Getters:
42 public static T_CAM_LiveStreamItemListener getCamLSIL() {
43 return camLSIL;
44 }
45
46 public static CBTHSettingsList getCBTHSettingsList() {
47 return cbthsl;
48 }
49
50 public static CommunicationRobotThread getCommunicatieRobot() {
51 return commRobot;
52 }
53
54 public static Cubie getCubie() {
55 return cubie;
56 }
57
58 public static B_SOLV_CubeToSolverListener getCubeToSolver() {
59 return cubeToSolver;
60 }
61
62 public static B_SOLV_MoveSeqToRobotListener getMoveSeqToRobot() {
63 return moveSeqToRobot;
64 }
65
66 // Setter:

Pagina 145 van 329 CubeThesis™ Depamelaere-Deschuytter


class CommonObjects

67 public static void setCamLSIL(T_CAM_LiveStreamItemListener camLSIListener) {


68 camLSIL = camLSIListener;
69 }
70 }

Pagina 146 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

1 package model;
2
3 import java.io.*;
4
5 import exceptions.CubeletAlreadyAssignedException;
6 import exceptions.FaceletColorNoneException;
7 import exceptions.NonExistingCubeletException;
8 import solver.solverJS.algorithm.CubePosition;
9 import solver.solverJS.viewSolverJS.Cubie;
10
11 public class CubeConfiguration {
12
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14 private static int[] startCubeletPerm;
15 private static int[] startCubeletOri;
16 private static int[] startFaceOri;
17 private static int[] colorMapKey;
18
19 // Getters:
20 public static int[] getColorMapKey() {
21 return colorMapKey;
22 }
23
24 public static int[] getStartCubeletOri() {
25 return startCubeletOri;
26 }
27
28 public static int[] getStartCubeletPerm() {
29 return startCubeletPerm;
30 }
31
32 public static int[] getStartFaceOri() {
33 return startFaceOri;
34 }
35
36 // Setters:
37 public static void setColorMapKey(int[] colorMapKey) {
38 CubeConfiguration.colorMapKey = colorMapKey;
39 }
40
41 public static void setStartCubeletOri(int[] startCubeletOri) {
42 CubeConfiguration.startCubeletOri = startCubeletOri;
43 }
44
45 public static void setStartCubeletPerm(int[] startCubeletPerm) {
46 CubeConfiguration.startCubeletPerm = startCubeletPerm;
47 }
48
49 public static void setStartFaceOri(int[] startFaceOri) {
50 CubeConfiguration.startFaceOri = startFaceOri;
51 }
52
53 // Static methods:
54 /**
55 * Will translate a cubeconfiguration from a set of maincubefaces to the
56 * "virtal cube format" Cubie requires.
57 *
58 * @param mainCubeFaces
59 * A set of six mainCubeFaces, to be found at the
60 * <code>CubeFacesList</code>.
61 */
62 public static void buildVirtualCube(CubeFace[] mainCubeFaces)
63 throws FaceletColorNoneException, NonExistingCubeletException,
64 CubeletAlreadyAssignedException {
65
66 System.out.println("Procedure to build the virtual cube was started...");

Pagina 147 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

67
68 System.out.println("-- VIRTUAL CUBE STAGE 1/7: Retrieving information "
69 + "upon the solver's cube-representation & extracting color-info "
70 + "from the main-cubefaces --");
71 int[][] cubelet2facelet = deepCopy(CubePosition.cubelet2facelet);
72 int[][] cubeletColors = deepCopy(CubePosition.cubeletColors);
73
74 int[][][] mainCubeFacesColors = new int[6][][];
75 for (int u = 0; u < mainCubeFacesColors.length; u++) {
76 mainCubeFacesColors[u] = mainCubeFaces[u].getColorsMatrix();
77 }
78
79 colorMapKey = null;
80
81 System.out.println("-- VIRTUAL CUBE STAGE 2/7: Checking main-cubefaces "
82 + "for the \"" + cbthsl.translateColorsIntToString(6) + "\" color --");
83 areAllFaceletsColored(mainCubeFaces);
84
85 int[] tempStartCubeletPerm = new int[26];
86
87 /* Initialize it on -1, since -1 is not a valid cubelet-id. */
88 for (int y = 0; y < tempStartCubeletPerm.length; y++) {
89 tempStartCubeletPerm[y] = -1;
90 }
91
92 int[] tempStartCubeletOri = new int[26];
93 int[] tempStartFaceOri = { 0, 0, 0, 0, 0, 0 };
94
95 System.out.println();
96 System.out.println("-- VIRTUAL CUBE STAGE 3/7: Linking facelet-colors "
97 + "to the appropriate cubelets --");
98
99 /*
100 * When a cube gets scrambled and randomly oriëntated, each faceletposition
101 * is even likely to show every color. In this stage, we imitate the
102 * cubeletColors-array, by retrieving the color that appears at each
103 * faceletposition. So the info yielded by the mainCubeFaces is framed here
104 * in a 2-dim array of the cubeletColors-type.
105 */
106 int[][] faceletColorsOfCubelets = new int[26][3];
107 int faceletID = -1;
108 for (int t = 0; t < cubelet2facelet.length; t++) {
109 // loop is executed 26x, for increasing cubelet-id.
110
111 for (int s = 0; s < cubelet2facelet[0].length; s++) {
112 faceletID = cubelet2facelet[t][s];
113 if (faceletID != -1) {
114 faceletColorsOfCubelets[t][s] = whatColorIsFacelet(mainCubeFacesColors,
115 faceletID);
116 } else {
117 faceletColorsOfCubelets[t][s] = -1;
118 }
119 }
120 }
121
122 String str1, str2, str3, str4;
123 str1 = " Array original cubelet-colors:";
124 System.out.print(str1 + amountOfSpaces(str1, 40));
125
126 for (int t = 0; t < cubeletColors.length; t++) {
127 str2 = "Cub. " + t + ": " + arrayPrint(cubeletColors[t], ", ");
128 System.out.print(str2 + amountOfSpaces(str2, 20));
129 }
130 System.out.println();
131
132 str3 = " Array detected cubelet-colors:";

Pagina 148 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

133 System.out.print(str3 + amountOfSpaces(str3, 40));


134 for (int t = 0; t < faceletColorsOfCubelets.length; t++) {
135 str4 = "Cub. " + t + ": " + arrayPrint(faceletColorsOfCubelets[t], ", ");
136 System.out.print(str4 + amountOfSpaces(str4, 20));
137 }
138 System.out.println();
139
140 System.out.println();
141 System.out.println("-- VIRTUAL CUBE STAGE 4/7: Identifying "
142 + "middlecubelets & Deducting colormapkey (array). --");
143 // System.out.println(" ---------------------");
144
145 /*
146 * Assigning a cubelet means its cubelet-id is written to some index of the
147 * tempStartCubeletPerm-array. In this stage, we only care about the
148 * middlecubelets. After all, it's their permutation that matters to
149 * determins the oriëntation of the cube's skeleton. The alreadyAssigned
150 * boolean below keeps record whether the cubelet considered had already
151 * been allocated somewhere else.
152 */
153
154 boolean[] alreadyAssigned = new boolean[26];
155 identifyPermOriCubeletsWithIdRange(alreadyAssigned, 20, tempStartCubeletPerm.length,
156 faceletColorsOfCubelets, cubeletColors, tempStartCubeletPerm,
157 tempStartCubeletOri);
158
159 /*
160 * Permutation of the middle-cubelets, is slightly differently digested by
161 * Cubie, as to say Cubie reacts with a recolouring operation. For the rest
162 * of the permutation-array nothing changes, but the sequence of the
163 * middle-cubelets. Cubie's visualisation is partly fooling the user. The
164 * sequel of the build procedure of the virtual cube, relies on the ability
165 * off recolouring the cube, hence allowing to permit all possible
166 * oriëntations, instead of restricting to "blue" must be the upper face,
167 * "yellow" the front... According to it's own logic - though this use was
168 * very carefully implemented and therefore intended-, the solver is
169 * slightly 'fooled'. In the end the user gets a 'right' impression of the
170 * situation, interpreting both it's vizualiation & genereated solving
171 * command's. To 'fool' the solver we will modify the local copy of the
172 * cubeletColors-matrix by using a further deduced colorMapKey-array. These
173 * modifications are accomplished between the identification of the
174 * middle-cubelets (stage 4) & rest of the cube (stage 6). In other words:
175 * The procedure basically anticipates on/uses the recolouring done by
176 * Cubie, by identifying other cubelets than would 'normally' be the case.
177 */
178
179 /*
180 * The new colors, are the numbers in the array and are mapped to the older
181 * colors, represented by the indexes. Due to 'deep'-copies of the
182 * cubeletColors- & cubelet2Facelet-matrices, original data from Cubie will
183 * not be affected by this colorremapping. Original cubecolor-data should
184 * remain intact, to assign the middle cubelets in Stage 4 during a next
185 * run.
186 */
187 colorMapKey = new int[6];
188
189 /*
190 * Permutation of the already assigned middle-cubelets is the only
191 * ingrediënt to the colorMapKey. tempStartCubeletPerm[i]-20 => Yields for
192 * the color of the middle-cubelet, according to the applied code (see Class
193 * CBTHSettingsList): Red=0, Blue=1... [i-20] specifies the old location
194 * where the new registered color is to be filled in.
195 */
196 for (int i = 20; i < tempStartCubeletPerm.length; i++) {
197 colorMapKey[i - 20] = tempStartCubeletPerm[i] - 20;
198 }

Pagina 149 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

199 System.out.println();
200 System.out.println(" Colormapkey-array: {" + arrayPrint(colorMapKey, ", ") + "}");
201
202 System.out.println();
203 System.out.println("-- VIRTUAL CUBE STAGE 5/7: Manipulating local "
204 + "copy of the cubeletcolors-matrix --");
205 int colorTemporary = -1;
206 // Achieved colorMapKey will now customize the cubeletColors-matrix.
207 int[][] newCubeletColors = new int[cubeletColors.length][cubeletColors[0].length];
208
209 for (int a = 0; a < newCubeletColors.length; a++) {
210 for (int b = 0; b < newCubeletColors[0].length; b++) {
211 colorTemporary = cubeletColors[a][b];
212 if (colorTemporary != -1) {
213 newCubeletColors[a][b] = colorMapKey[colorTemporary];
214 } else {
215 // Original fields containing '-1' shouldn't be
216 // translated, -1 is copied.
217 // Occurence of -1 means the actual cubelet isn't a
218 // corner-cubelet.
219 newCubeletColors[a][b] = -1;
220 }
221 }
222 }
223
224 /*
225 * NOTE: The middle-cubeletssection of the cubeletColors-matrix is also
226 * updated, however this was not strictly necessary. It won't cause any
227 * errors, since this is no longer needed.
228 */
229
230 str1 = " Array original cubeletcolors:";
231 System.out.print(str1 + amountOfSpaces(str1, 40));
232
233 for (int t = 0; t < cubeletColors.length; t++) {
234 str2 = "Blok " + t + ": " + arrayPrint(cubeletColors[t], ", ");
235 System.out.print(str2 + amountOfSpaces(str2, 20));
236 }
237 System.out.println();
238
239 /*
240 * Local copy of cubeletColors[][] is overwritten by the new info, yet a
241 * shallow copy would have been sufficient.
242 */
243 cubeletColors = deepCopy(newCubeletColors);
244
245 str1 = " Array manipulated cubeletcolors:";
246 System.out.print(str1 + amountOfSpaces(str1, 40));
247
248 for (int t = 0; t < cubeletColors.length; t++) {
249 str2 = "Blok " + t + ": " + arrayPrint(cubeletColors[t], ", ");
250 System.out.print(str2 + amountOfSpaces(str2, 20));
251 }
252 System.out.println();
253
254 System.out.println();
255 System.out.println("-- VIRTUAL CUBE STAGE 6/7: Identifying remaining "
256 + "corner- & edgecubelets with updated cubeletcolors-array. --");
257 // System.out.println(" ---------------------");
258
259 identifyPermOriCubeletsWithIdRange(alreadyAssigned, 0, 20, faceletColorsOfCubelets,
260 cubeletColors, tempStartCubeletPerm, tempStartCubeletOri);
261
262 System.out.println();
263 System.out.println("-- VIRTUAL CUBE STAGE 7/7: " + "Obtained cube-configuration --");
264 System.out.println();

Pagina 150 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

265
266 // Finally update the "start"-VirtualCube-array's.
267 setStartCubeletPerm(tempStartCubeletPerm);
268 setStartCubeletOri(tempStartCubeletOri);
269 setStartFaceOri(tempStartFaceOri);
270
271 // Last step: Virtual cube will be written to the screen.
272 System.out.println(cubeConfigPrint());
273
274 System.out.println(
275 "The procedure got finished without errors, " + "a virtual cube was built.");
276 }
277
278 // Static auxillary-methods below are listed alphabetically:
279
280 /**
281 * Goal: Faking a [TAB]. When notepad opens a Logfile, it replaces the [TAB]
282 * by another number of spaces, the console does. This will make both
283 * consistent. Min. amount of returned spaces is 1.
284 */
285 public static String amountOfSpaces(String str, int ref) {
286
287 StringBuffer sb = new StringBuffer(" ");
288
289 for (int i = 0; i < (ref - str.length()); i++) {
290 sb.append(" ");
291 }
292 return sb.toString();
293 }
294
295 /**
296 * Checks whether all facelets are coloured.
297 *
298 * @param mainCubeFaces
299 * Those six CubeFace's are hosted in CubeFacesList.
300 * @throws FaceletColorNoneException
301 */
302 public static void areAllFaceletsColored(CubeFace[] mainCubeFaces)
303 throws FaceletColorNoneException {
304
305 int[][] tempColorMatrix = null;
306 String nameCubeFace = null;
307 int u = 0, v = 0;
308
309 int cubeFaceIndex = 0;
310
311 // The program loops through the six faces.
312 while (cubeFaceIndex < 6) {
313
314 tempColorMatrix = mainCubeFaces[cubeFaceIndex].getColorsMatrix();
315 nameCubeFace = mainCubeFaces[cubeFaceIndex].toString();
316
317 u = 0;
318 while (u < tempColorMatrix.length) {
319 v = 0;
320 while (v < tempColorMatrix[0].length) {
321 if (tempColorMatrix[u][v] == 6) {
322 throw new FaceletColorNoneException(nameCubeFace, u, v);
323 }
324 v++;
325 }
326 u++;
327 }
328 cubeFaceIndex++;
329 System.out.println(" Main-cubeface: \"" + nameCubeFace + "\" was checked for \""
330 + cbthsl.translateColorsIntToString(6) + "\" color facelets.");

Pagina 151 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

331 }
332 }
333
334 /**
335 * Compares two int-array's. Returning false will request another shift of the
336 * faceletcolors.
337 *
338 * @param arrayA
339 * @param arrayB
340 * @return The returned boolean could be compared to the "errorsignal" in
341 * systemtheory.
342 */
343 public static boolean arrayComparision(int[] arrayA, int[] arrayB) {
344
345 boolean areEqual = false;
346
347 if (arrayA.length == arrayB.length) { // Als arrayA en arrayB al
348 // niet dezelfde lengte hebben, moet er niet meer verder worden
349 // gecontroleerd.
350 areEqual = true;
351 int index = 0;
352 while (index < arrayA.length && areEqual) {
353 if (arrayA[index] != arrayB[index]) {
354 areEqual = false;
355 }
356 index++;
357 }
358 }
359 return areEqual;
360 }
361
362 /**
363 * Returns the array without '-1'-fields at the end.
364 *
365 * @param array
366 * The input must be an int-array
367 * @return array that has length &#60;= original.length
368 */
369 public static int[] arrayOmitMinusOne(int[] array) {
370
371 int[] arrayToReturn = null;
372 int timesMinOne = countTimesMinOne(array);
373
374 if (timesMinOne > 0) { // If true, we don't deal with a corner-cubelet.
375 arrayToReturn = new int[array.length - timesMinOne];
376
377 // A deep partial deep copy is organized till the returned array
378 // is filled.
379 for (int r = 0; r < arrayToReturn.length; r++) {
380 arrayToReturn[r] = array[r];
381 }
382 }
383
384 else { // We deal with a corner-cubelelt, there's no copying needed.
385 arrayToReturn = array;
386 }
387 return arrayToReturn;
388 }
389
390 /** Generates a textual representation of a 1-dim array. */
391 public static String arrayPrint(int[] array, String enumerationSign) {
392
393 int i = 0;
394 StringBuffer sb = new StringBuffer();
395
396 while (i < array.length - 1) {

Pagina 152 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

397 sb.append(array[i] + enumerationSign);


398 i++;
399 }
400
401 // After last element, no more comma is written.
402 sb.append(array[i]);
403
404 return sb.toString();
405 }
406
407 /**
408 * The operation taking place in this method is what one would call a $
409 * "SHIFT"-instruction in a PLC environment. However integers are involved
410 * here instead of bits.
411 *
412 * @param array
413 * The int-array on which the shifting will take place.
414 * @param rotationNumber
415 * Specifies the number of places the array shifts.
416 * @return the shifted int-array.
417 */
418 public static int[] arrayShiftLeft(int[] array, int rotationNumber) {
419
420 int[] resultArray = new int[array.length];
421 // Auxillary array to save the first #rotationNumber numbers from
422 // being overwritten in phase 2.
423 int[] auxillaryArray = new int[rotationNumber];
424
425 /*
426 * The principle of next lines won't allow for
427 * rotationNumber's>array.length. Errors are avoided by passing the
428 * remainder of the division of the specified rotationNumber by the
429 * array.length instead of passing the rotationNumber itself. So if some
430 * array contains 3 numbers, a shift of 3 would result in 0.
431 */
432 rotationNumber = rotationNumber % array.length;
433
434 if (rotationNumber != 0) {
435 // Phase 1: auxillaryArray copies numbers that risk being overwritten.
436 for (int u = 0; u < rotationNumber; u++) {
437 auxillaryArray[u] = array[u];
438 }
439
440 // Phase 2: Remaining numbers in the array are shifted
441 // #rotationNumber places to the left.
442 for (int v = rotationNumber; v < array.length; v++) {
443 resultArray[v - rotationNumber] = array[v];
444 }
445
446 /*
447 * Phase 3: To complete the array, the auxillary bit will be added again
448 * at the end. Would this piece be inverted, then a so called "ROTATE"
449 * PLC-Instruction would be implemented.
450 */
451 for (int w = 0; w < auxillaryArray.length; w++) {
452 resultArray[array.length - rotationNumber + w] = auxillaryArray[w];
453 }
454 } else {
455 resultArray = array;
456 }
457 return resultArray;
458 }
459
460 /**
461 * Loads the cubeconfiguration from the savefile.
462 *

Pagina 153 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

463 * @param dis


464 * DataInputStream-object reads the data.
465 * @throws IOException
466 */
467 public static void cubeConfigFromSaveFile(DataInputStream dis) throws IOException {
468 int[][] cubeConfigMatrix = new int[4][];
469
470 int j = 0;
471 for (int c = 0; c < cubeConfigMatrix.length; c++) {
472 int l = dis.readInt();
473 cubeConfigMatrix[c] = new int[l];
474 for (j = 0; j < l; j++) {
475 cubeConfigMatrix[c][j] = dis.readInt();
476 }
477 }
478 startCubeletPerm = cubeConfigMatrix[0];
479 startCubeletOri = cubeConfigMatrix[1];
480 startFaceOri = cubeConfigMatrix[2];
481 colorMapKey = cubeConfigMatrix[3];
482
483 Cubie cubie = CommonObjects.getCubie();
484 cubie.cubieSetCube(deepCopy(startCubeletPerm), deepCopy(startCubeletOri),
485 deepCopy(startFaceOri));
486 }
487
488 /**
489 * Saves the current cubeconfiguration to the savefile.
490 *
491 * @param dos
492 * DataOuputStream-object that writes the data.
493 * @throws IOException
494 */
495 public static void cubeConfigToSaveFile(DataOutputStream dos) throws IOException {
496
497 int[][] cubeConfigMatrix = new int[4][];
498 cubeConfigMatrix[0] = startCubeletPerm;
499 cubeConfigMatrix[1] = startCubeletOri;
500 cubeConfigMatrix[2] = startFaceOri;
501 cubeConfigMatrix[3] = colorMapKey;
502
503 int l = 0;
504 for (int c = 0; c < cubeConfigMatrix.length; c++) {
505 dos.writeInt(cubeConfigMatrix[c].length);
506 for (l = 0; l < cubeConfigMatrix[c].length; l++) {
507 dos.writeInt(cubeConfigMatrix[c][l]);
508 }
509 }
510 }
511
512 /**
513 * Will count the occurrence of '-1' in the specified int-array.
514 */
515 public static int countTimesMinOne(int[] inputArray) {
516 int result = 0;
517 for (int i = 0; i < inputArray.length; i++) {
518 if (inputArray[i] == -1) {
519 result++;
520 }
521 }
522 return result;
523 }
524
525 /** Generates a textual representation of the virtual cube. */
526 public static String cubeConfigPrint() {
527
528 StringBuffer sb = new StringBuffer();

Pagina 154 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

529 String newLine = cbthsl.getString("newLine");


530 sb.append("Colormapkey: {" + arrayPrint(colorMapKey, ", "));
531 sb.append("}" + newLine + newLine);
532
533 String[] prefix = { " //", "||", "||", "||", " \\\\" };
534 sb.append(prefix[0] + newLine);
535
536 // CubeletPerm
537 sb.append(prefix[1] + "CubeletPerm: {");
538 sb.append(arrayPrint(startCubeletPerm, ", ") + "}" + newLine);
539
540 // CubeletOri
541 sb.append(prefix[2] + "CubeletOri: {");
542 sb.append(arrayPrint(startCubeletOri, ", ") + "}" + newLine);
543
544 // FaceOri
545 sb.append(prefix[3] + "FaceOri: {");
546 sb.append(arrayPrint(startFaceOri, ", ") + "}" + newLine);
547
548 sb.append(prefix[4] + newLine);
549
550 return sb.toString();
551 }
552
553 /**
554 * Generates a textual representation of some cubelet's colors.
555 *
556 * @param faceletColors
557 * int-array input
558 */
559 public static String cubeletColorsToString(int[] faceletColors) {
560
561 StringBuffer sb = new StringBuffer();
562
563 faceletColors = arrayOmitMinusOne(faceletColors);
564
565 sb.append("[");
566 int r = 0;
567
568 while (r < faceletColors.length - 1) {
569 sb.append(cbthsl.translateColorsIntToString(faceletColors[r]) + ", ");
570 r++;
571 }
572 sb.append(cbthsl.translateColorsIntToString(faceletColors[r]) + "]");
573
574 return sb.toString();
575 }
576
577 /** Returns a deep copy from specified array. */
578 public static int[] deepCopy(int[] array) {
579 int[] arrayToReturn = new int[array.length];
580 for (int a = 0; a < arrayToReturn.length; a++) {
581 arrayToReturn[a] = array[a];
582 }
583 return arrayToReturn;
584 }
585
586 /** Returns deep copy from specified matrix. */
587 public static int[][] deepCopy(int[][] matrix) {
588 int[][] matrixToReturn = new int[matrix.length][];
589 for (int a = 0; a < matrixToReturn.length; a++) {
590 /*
591 * Second dimension of the matrix, doesn't need to have constant length.
592 * for each index in the first dimension, a second array is created with a
593 * length at wish.
594 */

Pagina 155 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

595 matrixToReturn[a] = new int[matrix[a].length];


596 for (int b = 0; b < matrix[a].length; b++) {
597 matrixToReturn[a][b] = matrix[a][b];
598 }
599 }
600 return matrixToReturn;
601 }
602
603 /**
604 * Identifies both the permutation and orientation of cubelets within a
605 * indicated id range.
606 *
607 * @param alreadyAssigned
608 * for each Cubelet-id/index, true means it was already assigned.
609 * @param startCubelet
610 * This is the iD of the cubelet, that occupies the startingposition
611 * of this range, in a solved cubestate.
612 * @param stopCubelet
613 * This is the iD of the cubelet, that occupies the stoppingposition
614 * of this range, in a solved cubestate.
615 * @param faceletColorsOfCubelets
616 * Contains the info retrieved from the mainCubeFaces.
617 * @param cubeletColors
618 * The cubeletColor information is passed, whether modified or not.
619 * @param tempStartCubeletPerm
620 * The first array of the virtual cube.
621 * @param tempStartCubeletOri
622 * The second array of the virtual cube.
623 * @throws NonExistingCubeletException
624 * @throws CubeletAlreadyAssignedException
625 */
626 public static void identifyPermOriCubeletsWithIdRange(boolean[] alreadyAssigned,
627 int startCubelet, int stopCubelet, int[][] faceletColorsOfCubelets,
628 int[][] cubeletColors, int[] tempStartCubeletPerm, int[] tempStartCubeletOri)
629 throws NonExistingCubeletException, CubeletAlreadyAssignedException {
630
631 int[] shallowCopyOfFaceletColors;
632 int resultPerm;
633 int resultOri;
634
635 for (int p = startCubelet; p < stopCubelet; p++) {
636 shallowCopyOfFaceletColors = faceletColorsOfCubelets[p];
637 resultPerm = retrieveCubeletIdByFaceletColors(cubeletColors,
638 shallowCopyOfFaceletColors);
639 resultOri = 0;
640
641 // If we face an unkown cubelet, continuation of the process won't make
642 // big sense.
643 if (resultPerm == -1) {
644 throw new NonExistingCubeletException(shallowCopyOfFaceletColors,
645 cubeletColors[p]);
646 }
647
648 if (alreadyAssigned[resultPerm]) {
649 /*
650 * Being true means the actual cubelet with the detected id, was already
651 * assigned elsewhere. Since allocation of the specified range happens
652 * from left to right, algorithm-speed can be gained by limiting to the
653 * left-part of the array.
654 */
655 int[] partlyDeepCopy = new int[p];
656 for (int t = 0; t < partlyDeepCopy.length; t++) {
657 partlyDeepCopy[t] = tempStartCubeletPerm[t];
658 }
659 int twinPosition = positionNumberInArray(partlyDeepCopy, resultPerm);
660 String colorsDisputedCubelet = cubeletColorsToString(cubeletColors[resultPerm]);

Pagina 156 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

661 /*
662 * The locations where the error occurred don't need extra intervention
663 * from the colorMapKey Attention to colorsLocation1/2 when
664 * middle-cubelets are involved: there's no recolouring done yet.
665 */
666 String colorsLocation1 = cubeletColorsToString(cubeletColors[twinPosition]);
667 String colorsLocation2 = cubeletColorsToString(cubeletColors[p]);
668
669 throw new CubeletAlreadyAssignedException(resultPerm, colorsDisputedCubelet,
670 colorsLocation1, colorsLocation2);
671 } else {
672 // If the actual cubelet is a middle-cubelet, then the oriëntation
673 // should not be retrieved.
674 if (resultPerm < 20) {
675 resultOri = retrieveCubeletOrientation(cubeletColors[resultPerm],
676 shallowCopyOfFaceletColors);
677 }
678 // Allocation to local arrays. Since everything went ok,
679 // set the concerned boolean in alreadyAssigned true.
680 tempStartCubeletPerm[p] = resultPerm;
681 tempStartCubeletOri[p] = resultOri;
682 alreadyAssigned[resultPerm] = true;
683 System.out.println(" Cubelet \"" + resultPerm
684 + "\" was succesfully identified & was allocated orientation \"" + resultOri
685 + "\".");
686 // System.out.println(" ---------------------");
687 }
688 }
689 }
690
691 /**
692 * Returns the first index of occurrence of the specified number. If the
693 * number wasn't found, -1 is returned.
694 *
695 * @param array
696 * @param numberToFind
697 * @return returns the first index of occurrence of the numberToFind.
698 */
699 public static int positionNumberInArray(int[] array, int numberToFind) {
700
701 boolean arrayContainsNumber = false;
702 int index = 0;
703 while (index < array.length && !arrayContainsNumber) {
704 if (array[index] == numberToFind) {
705 arrayContainsNumber = true;
706 } else {
707 index++;
708 }
709 }
710 if (!arrayContainsNumber) {
711 index = -1;
712 }
713 return index;
714 }
715
716 /**
717 * Retrieves the CubeletId by looping through the possibilities as efficient
718 * as possible.
719 *
720 * @param cubeletColors
721 * The modified color information from Cubie
722 * @param faceletColorsOfCubelet
723 * The actual colors detected at this cubeletPosition.
724 * @return returns the detected cubelet-iD, if nothing was detected '-1' was
725 * returned.
726 */

Pagina 157 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

727 public static int retrieveCubeletIdByFaceletColors(int[][] cubeletColors,


728 int[] faceletColorsOfCubelet) {
729
730 int a = faceletColorsOfCubelet[0];
731 int b = faceletColorsOfCubelet[1];
732 int c = faceletColorsOfCubelet[2];
733
734 int cubeletType = countTimesMinOne(faceletColorsOfCubelet);
735
736 int[] cbltClrsDeepCopy;
737 int posInArray1 = -1;
738 int posInArray2 = -1;
739
740 int number = -1;
741 int upperLimit = 0;
742 int underLimit = 0;
743 boolean alreadyFound = false;
744
745 // Cubelettype-dependent upper- & lowerbound depending are imposed to
746 // ease the job.
747 switch (cubeletType) {
748 case 0:
749 underLimit = 0;
750 upperLimit = 8;
751 break;
752 // It concerns a corner-cubelet
753 case 1:
754 underLimit = 8;
755 upperLimit = 20;
756 break;
757 // It concerns an edge-cubelet
758 case 2:
759 underLimit = 20;
760 upperLimit = 26;
761 break;
762 // It concerns a middle-cubelet
763 default:
764 System.err.println("ERROR: Some cubelet pretends not to "
765 + "be either of corner/edge/middle-type.");
766 break;
767 }
768
769 /*
770 * NOTE: Important property of a 3x3 cube: Each edge-cubelet is unique,
771 * hence a colorcombination of facelets yields to the identification of that
772 * cubelet. A 4x4x4 cube e.g. has two edge-cubelets with the same colors, so
773 * mere color-info is no longer sufficient. For increasing order of the
774 * cube, also more color-identical 'middle'-cubelets have to be taken into
775 * account.
776 */
777
778 number = underLimit;
779 while (number < upperLimit && !alreadyFound) {
780
781 // To save time, the conditions are nested. When the first is
782 // not agreed, the others are not even considered.
783
784 /*
785 * A deep copy of cubeletColors[number] is desired since detected values
786 * will be overwritten with '-2'. At first sight a, b & c are always
787 * different numbers and so do cubeletColors[number], but for
788 * middle-cubelets, 2x '-1' should be detected. If the first '-1' would
789 * not be overwritten by '-2', then 4 edge-cubelets would also fit.
790 * However, this problem will not occur, given the upper- & lowerbound
791 * that were specified.
792 */

Pagina 158 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

793 cbltClrsDeepCopy = deepCopy(cubeletColors[number]);


794
795 posInArray1 = positionNumberInArray(cbltClrsDeepCopy, a);
796
797 if (posInArray1 != -1) {
798 cbltClrsDeepCopy[posInArray1] = -2;
799 posInArray2 = positionNumberInArray(cbltClrsDeepCopy, b);
800
801 if (posInArray2 != -1) {
802 cbltClrsDeepCopy[posInArray2] = -2;
803
804 /*
805 * Two out of three numbers are yet detected. The sum of the indexes
806 * in cbltClrsDeepCopy = 3. So the array-number left to detect should
807 * be located at [3-posInArray1-posInArray2]. This saves another call
808 * for the positionNumberInArray(cbltClrsDeepCopy, c)
809 */
810 if (cbltClrsDeepCopy[3 - posInArray1 - posInArray2] == c) {
811 alreadyFound = true;
812 }
813 }
814 }
815 number++;
816 }
817
818 if (alreadyFound) {
819 return number - 1;// '-1' compensates for the incrementing
820 // after the cubelet is detected.
821 } else {
822 return -1;
823 }
824 }
825
826 /**
827 * Yields for the cubelet's orientation, by running an iterative
828 * comparitionprocess.
829 *
830 * @param cubeletColors
831 * @param faceletColorsOfCubelet
832 * @return An int which represents the orientation of the cubelet.
833 */
834 public static int retrieveCubeletOrientation(int[] cubeletColors,
835 int[] faceletColorsOfCubelet) {
836
837 int orientationToReturn = 0;
838 int maximum = 0;
839 boolean orientationFound = false;
840
841 /*
842 * In the first step, the '-1'-fields are omitted. Checks are altered with
843 * shifts, in an iterative process. In this method the cubeletColors are
844 * shifted left, then compared to the faceletColors and so on... But of
845 * course, shifting the actual faceletColors to the right would yield to the
846 * very same result.
847 */
848
849 int[] arrayA = arrayOmitMinusOne(cubeletColors);
850 int[] arrayB = arrayOmitMinusOne(faceletColorsOfCubelet);
851
852 /*
853 * //Some more outprint if desired. System.out.print("\tArrayA: ");
854 * System.out.println(arrayPrint(arrayA, ", "));
855 *
856 * System.out.print("\tArrayB: "); System.out.println(arrayPrint(arrayB,
857 * ", "));
858 */

Pagina 159 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeConfiguration

859
860 maximum = arrayB.length;
861
862 while (orientationToReturn < maximum && !orientationFound) {
863
864 if (arrayComparision(arrayA, arrayB)) {
865 orientationFound = true;
866 /*
867 * System.out.println("\tArray A\t| Array B"); for(int u=0;
868 * u<arrayA.length; u++){ System.out.println("\tA:"+arrayA[u]+"\t| B:"
869 * +arrayB[u]); }
870 */
871 } else {
872 orientationToReturn++;
873 arrayA = arrayShiftLeft(arrayA, 1);
874 }
875 }
876 /*
877 * Excessive orientations will invoke errors in Cubie. Though not strictly
878 * necessary, it's safe to pass the remainder of the division
879 * ori(..)turn/maximum...
880 */
881 return orientationToReturn % maximum;
882 }
883
884 /**
885 * Given a facelet-iD, and the mainCubeFaces-array, this method will return
886 * the color detected at that place.
887 *
888 * @param mainCubeFacesColors
889 * @param faceletID
890 * Facelet-Id of whom the color should be known.
891 * @return int value that represents color.
892 */
893 public static int whatColorIsFacelet(int[][][] mainCubeFacesColors, int faceletID) {
894
895 int a = -1, b = -1, c = -1, remaindr = -1;
896 a = faceletID / 9;
897 remaindr = faceletID % 9;
898 b = remaindr / 3;
899 c = remaindr % 3;
900
901 return mainCubeFacesColors[a][b][c];
902 }
903 }

Pagina 160 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeFace

1 package model;
2
3 import java.io.*;
4 import java.util.Observable;
5
6 import view.VisualCubeFace;
7
8 public class CubeFace extends Observable {
9
10 private int iD;
11 private String name;
12 private static int iDGenerator = 0;
13 private int[][] colorsMatrix;
14 private double[][] confidenceMatrix;
15 private int[][] noneColorsMatrix = { { 6, 6, 6 }, { 6, 6, 6 }, { 6, 6, 6 } };
16 private VisualCubeFace vcf;
17
18 // Constructors:
19 public CubeFace() {
20
21 this.iD = iDGenerator;
22 this.name = null;
23 this.colorsMatrix = new int[3][3];
24 this.confidenceMatrix = new double[3][3];
25 this.setCubeFaceDeepCopy(noneColorsMatrix, new double[3][3]);
26 this.vcf = createVCubeFace();
27
28 iDGenerator++;
29 }
30
31 public CubeFace(String name, int colorsMatrix[][], double confidenceMatrix[][]) {
32
33 iD = iDGenerator;
34 this.name = name;
35 this.colorsMatrix = new int[3][3];
36 this.confidenceMatrix = new double[3][3];
37
38 if (colorsMatrix != null && confidenceMatrix != null) {
39 this.setCubeFaceDeepCopy(colorsMatrix, confidenceMatrix);
40 }
41
42 else {
43 this.setCubeFaceDeepCopy(noneColorsMatrix, new double[3][3]);
44 }
45 this.vcf = createVCubeFace();
46 // System.out.println("A new CubeFace with iD: \""+iD+"\" was created.");
47 iDGenerator++;
48 }
49
50 // Getters:
51 public int[][] getColorsMatrix() {
52 return this.colorsMatrix;
53 }
54
55 public int getColorValue(int r, int k) {
56 return colorsMatrix[r][k];
57 }
58
59 public double[][] getConfidenceMatrix() {
60 return this.confidenceMatrix;
61 }
62
63 public int getID() {
64 return this.iD;
65 }
66

Pagina 161 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeFace

67 public static int getIDGenerator() {


68 return iDGenerator;
69 }
70
71 public VisualCubeFace getVisualCubeFace() {
72 return vcf;
73 }
74
75 // Setters:
76 /**
77 * Will alter the color-value of specified row, col. No updateVisualCubeFace()
78 * is needed, since it happens collectively. It was made private because the
79 * method is only used by this Class.
80 *
81 * @param colorValue
82 * the new color.
83 * @param r
84 * row number
85 * @param c
86 * column number
87 */
88 private void setColorValue(int colorValue, int r, int c) {
89 colorsMatrix[r][c] = colorValue;
90 }
91
92 /**
93 * Will alter the confidence-level of specified row, col. No
94 * updateVisualCubeFace() is needed, since it happens collectively. It was
95 * made private because the method is only used by this Class.
96 *
97 * @param confidenceLevel
98 * The new confidence level.
99 * @param r
100 * row number
101 * @param c
102 * column number
103 */
104 private void setConfidenceLevel(double confidenceLevel, int r, int c) {
105 confidenceMatrix[r][c] = confidenceLevel;
106 }
107
108 /** Organizes a deep copy of a CubeFace. */
109 public void setCubeFaceDeepCopy(int[][] newColorMatrix,
110 double[][] newConfidenceMatrix) {
111
112 for (int g = 0; g < colorsMatrix.length; g++) {
113 for (int h = 0; h < colorsMatrix[0].length; h++) {
114 this.colorsMatrix[g][h] = newColorMatrix[g][h];
115 this.confidenceMatrix[g][h] = newConfidenceMatrix[g][h];
116 }
117 }
118 updateVisualCubeFace();
119 }
120
121 /** Changes one color and confidence level. */
122 public void setOneColorOneConfidenceLevel(int colorValue, double confidenceLevel,
123 int row, int column) {
124
125 setColorValue(colorValue, row, column);
126 setConfidenceLevel(confidenceLevel, row, column);
127
128 updateVisualCubeFace();
129 }
130
131 // Instance methods:
132 /**

Pagina 162 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeFace

133 * Automatic routine calls for this method to check if the confidence level
134 * reaches the threshold.
135 */
136 public boolean confidenceLevelSufficient(double thresholdColorEstimation) {
137 boolean sufficient = true;
138 int i = 0, j = 0;
139
140 /*
141 * The use of while loops, allows to stop searching at the first occurrence
142 * of a facelet with low confidence level.
143 */
144 while (i < confidenceMatrix.length && sufficient) {
145 while (j < confidenceMatrix[0].length && sufficient) {
146 if (confidenceMatrix[i][j] < thresholdColorEstimation) {
147 sufficient = false;
148 }
149 j++;
150 }
151 i++;
152 }
153 return sufficient;
154 }
155
156 /**
157 * This method is needed for the constructors and for the
158 * color-recognitionprocess. But navigating on tab [CUBE] is done with
159 * getVisualCubeFace().
160 *
161 * @return VisualCubeFace Returns a new visual representation of the cubeface.
162 */
163 public VisualCubeFace createVCubeFace() {
164
165 VisualCubeFace visualCF = new VisualCubeFace(this);
166 this.addObserver(visualCF);
167
168 updateVisualCubeFace();
169
170 return visualCF;
171 }
172
173 public void cubeFaceToSaveFile(DataOutputStream dos) throws IOException {
174
175 boolean colorsMatrixDiffersFromNull = colorsMatrix != null;
176
177 dos.writeBoolean(colorsMatrixDiffersFromNull);
178
179 if (colorsMatrixDiffersFromNull) {
180
181 for (int r = 0; r < colorsMatrix.length; r++) {
182 for (int s = 0; s < colorsMatrix[0].length; s++) {
183 dos.writeInt(colorsMatrix[r][s]);
184 }
185 }
186 }
187
188 boolean confidenceMatrixDiffersFromNull = confidenceMatrix != null;
189
190 dos.writeBoolean(confidenceMatrixDiffersFromNull);
191
192 if (confidenceMatrixDiffersFromNull) {
193
194 for (int r = 0; r < confidenceMatrix.length; r++) {
195 for (int s = 0; s < confidenceMatrix[0].length; s++) {
196 dos.writeDouble(confidenceMatrix[r][s]);
197 }
198 }

Pagina 163 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeFace

199 }
200 }
201
202 /**
203 * Rotates the CubeFace see tab [CUBE]
204 *
205 * @param clockwise
206 * true=CLKW, false=CNTRCLKW
207 */
208 public void rotateCubeFace(boolean clockwise) {
209
210 int[][] tempColorsMatrix = new int[3][3];
211 double[][] tempConfidenceMatrix = new double[3][3];
212
213 if (clockwise) { // Clockwise 90°
214 for (int i = 0; i < tempColorsMatrix.length; i++) {
215 for (int j = 0; j < tempColorsMatrix[0].length; j++) {
216 tempColorsMatrix[i][j] = colorsMatrix[2 - j][i];
217 tempConfidenceMatrix[i][j] = confidenceMatrix[2 - j][i];
218 }
219 }
220 colorsMatrix = tempColorsMatrix;
221 confidenceMatrix = tempConfidenceMatrix;
222 } else { // Counterclockwise 90°
223 for (int i = 0; i < tempColorsMatrix.length; i++) {
224 for (int j = 0; j < tempColorsMatrix[0].length; j++) {
225 tempColorsMatrix[i][j] = colorsMatrix[j][2 - i];
226 tempConfidenceMatrix[i][j] = confidenceMatrix[j][2 - i];
227 }
228 }
229 colorsMatrix = tempColorsMatrix;
230 confidenceMatrix = tempConfidenceMatrix;
231 }
232 updateVisualCubeFace();
233 }
234
235 @Override
236 /** Textual representation */
237 public String toString() {
238 return this.iD + ". " + this.name;
239 }
240
241 /**
242 * This method is part of the Observer-Observable technique. It will trigger
243 * its Observers.
244 */
245 public void updateVisualCubeFace() {
246
247 setChanged();
248 notifyObservers();
249 }
250 }

Pagina 164 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeFacesList

1 package model;
2
3 import java.io.*;
4 import java.util.*;
5
6 import exceptions.NumberNotFoundException;
7 import model.CubeFace;
8
9 public class CubeFacesList extends Observable {
10
11 private static String[] mainCubeFacesNames = { "LeftFace", "UpperFace", "FrontFace",
12 "RightFace", "DownFace", "BackFace" };
13 private ArrayList<CubeFace> cubeFacesList;
14 private CubeFace[] mainCubeFacesList = new CubeFace[6];
15
16 // Constructor:
17 public CubeFacesList() {
18
19 cubeFacesList = new ArrayList<CubeFace>();
20 CubeFace cf;
21
22 for (int k = 0; k < mainCubeFacesNames.length; k++) {
23 cf = new CubeFace(mainCubeFacesNames[k], null, null);
24 mainCubeFacesList[k] = cf;
25 }
26 }
27
28 // Getters:
29 public CubeFace[] getAllMainCubeFaces() {
30 return mainCubeFacesList;
31 }
32
33 public CubeFace getCubeFace(int i) {
34 return cubeFacesList.get(i);
35 }
36
37 public List<CubeFace> getCubeFacesList() {
38 return cubeFacesList;
39 }
40
41 public CubeFace getMainCubeFace(int i) {
42 return mainCubeFacesList[i];
43 }
44
45 public int getSize() {
46 return cubeFacesList.size();
47 }
48
49 // Instance methods:
50 public void addCubeFace(CubeFace v) {
51
52 if (v != null) {
53 cubeFacesList.add(v);
54 System.out.println("Cubeface \"" + v.getID() + "\" was added to the "
55 + "cubeFacesList succesfully.");
56 updateCubeFaces();
57 }
58 }
59
60 public void cubeFacesFromSaveFile(DataInputStream dis) throws IOException {
61
62 int amountOfCubeFaces = dis.readInt();
63
64 int[][] newColorsMatrix = null;
65 double[][] newConfidenceMatrix = null;
66

Pagina 165 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeFacesList

67 for (int u = 0; u < amountOfCubeFaces; u++) {


68
69 newColorsMatrix = new int[3][3];
70 newConfidenceMatrix = new double[3][3];
71
72 if (singleCubeFaceFromSaveFile(dis, newColorsMatrix, newConfidenceMatrix)) {
73 newColorsMatrix = null;
74 newConfidenceMatrix = null;
75 }
76
77 CubeFace cf = new CubeFace(null, newColorsMatrix, newConfidenceMatrix);
78 addCubeFace(cf);
79 cf = null;
80
81 newColorsMatrix = null;
82 newConfidenceMatrix = null;
83 }
84 }
85
86 /** Saves the entire cubeFacesList, shown in the lowerpanel of tab [CUBE]. */
87 public void cubeFacesToSaveFile(DataOutputStream dos) throws IOException {
88
89 for (CubeFace v : cubeFacesList) {
90 v.cubeFaceToSaveFile(dos);
91 }
92 }
93
94 public void deleteAllCubeFaces() {
95
96 cubeFacesList.clear();
97 updateCubeFaces();
98 }
99
100 public void deleteCubeFace(int iD) throws NumberNotFoundException {
101
102 cubeFacesList.remove(searchIndexOfCubeFaceOnID(iD));
103 updateCubeFaces();
104 }
105
106 public void mainCubeFacesFromSaveFile(DataInputStream dis) throws IOException {
107
108 final int[][] noneColorsMatrix = { { 6, 6, 6 }, { 6, 6, 6 }, { 6, 6, 6 } };
109 int[][] newColorsMatrix = null;
110 double[][] newConfidenceMatrix = null;
111
112 for (int k = 0; k < mainCubeFacesList.length; k++) {
113
114 newColorsMatrix = new int[3][3];
115 newConfidenceMatrix = new double[3][3];
116
117 if (singleCubeFaceFromSaveFile(dis, newColorsMatrix, newConfidenceMatrix)) {
118 newColorsMatrix = noneColorsMatrix;
119 }
120
121 // No new CubeFace-objects are made, since we want to keep their names.
122 mainCubeFacesList[k].setCubeFaceDeepCopy(newColorsMatrix, newConfidenceMatrix);
123 mainCubeFacesList[k].updateVisualCubeFace();
124 newColorsMatrix = null;
125 newConfidenceMatrix = null;
126 }
127 }
128
129 public void mainCubeFacesToSaveFile(DataOutputStream dos) throws IOException {
130
131 for (CubeFace v : mainCubeFacesList) {
132 v.cubeFaceToSaveFile(dos);

Pagina 166 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeFacesList

133 }
134 }
135
136 public void resetMainCubeFaces() {
137
138 final int[][] noneColorsMatrix = { { 6, 6, 6 }, { 6, 6, 6 }, { 6, 6, 6 } };
139 double[][] tempConfidenceMatrix = new double[3][3];
140
141 for (int k = 0; k < mainCubeFacesList.length; k++) {
142 // No new CubeFace-objects are made, since we want to keep
143 // their names.
144 mainCubeFacesList[k].setCubeFaceDeepCopy(noneColorsMatrix, tempConfidenceMatrix);
145 }
146 }
147
148 /**
149 * ID is an attribute of the CubFace-object which is unique in one
150 * CubeThesis-session and stays coupled to the CubeFace-object. The index of
151 * the CubeFaces can alter, e.g. when removing items in the ArrayList.
152 */
153 public int searchIndexOfCubeFaceOnID(int nr) throws NumberNotFoundException {
154
155 CubeFace cf = null;
156 boolean alreadyFound = false;
157 int c = 0, a = cubeFacesList.size();
158
159 while (c < a && !alreadyFound) {
160 cf = getCubeFace(c);
161 if (nr == cf.getID()) {
162 alreadyFound = true;
163 } else {
164 c++;
165 }
166 }
167 if (!alreadyFound) {
168 throw new NumberNotFoundException("the cubefaceslist");
169 }
170 return c;
171 }
172
173 public static boolean singleCubeFaceFromSaveFile(DataInputStream dis,
174 int[][] colorsMatrix, double[][] confidenceMatrix) throws IOException {
175
176 boolean boola = false, boolb = false;
177 if (boola = dis.readBoolean()) {
178
179 for (int a = 0; a < colorsMatrix.length; a++) {
180 for (int b = 0; b < colorsMatrix[0].length; b++) {
181 colorsMatrix[a][b] = dis.readInt();
182 }
183 }
184 }
185
186 if (boolb = dis.readBoolean()) {
187
188 for (int a = 0; a < confidenceMatrix.length; a++) {
189 for (int b = 0; b < confidenceMatrix[0].length; b++) {
190 confidenceMatrix[a][b] = dis.readDouble();
191 }
192 }
193 }
194 return !boola && !boolb;
195 }
196
197 /**
198 * This method is part of the Observer-Observable technique. It will trigger

Pagina 167 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubeFacesList

199 * its Observers.


200 */
201 public void updateCubeFaces() {
202 setChanged();
203 notifyObservers();
204 }
205 }

Pagina 168 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

1 package solver.solverJS.algorithm;
2
3 public class CubePosition {
4
5 // These 3 array's represent the cube in the Cubie-applet:
6 public final int cubeletPerm[];
7 public final int cubeletOri[];
8 public final int faceOri[];
9
10 // Is used for Symmetry-tests.
11 static final int pceTypes[] = { 20, 26, 4, 0, 8, 3, 8, 20, 2 };
12
13 // conversion from move number to action on internal cube representation
14 // L U F R D B Lc Uc Fc
15 final int movePerm[][][] = {
16 // piece perm/ori, relabel perm/ori, color perm
17 { // L
18 { 0, 1, 3, 7, 4, 5, 2, 6, 8, 9, 15, 11, 12, 13, 10, 18, 16, 17, 14, 19, 20, 21,
19 22, 23, 24, 25 },
20 { 0, 0, 2, 1, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 3, 0, 0, 0, 0,
21 0 },
22 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
23 22, 23, 24, 25 },
24 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25 0 },
26 { 0, 0, 0, 0, 0, 0 } },
27 { // U
28 { 3, 0, 1, 2, 4, 5, 6, 7, 11, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
29 22, 23, 24, 25 },
30 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,
31 0 },
32 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
33 22, 23, 24, 25 },
34 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35 0 },
36 { 0, 0, 0, 0, 0, 0 } },
37 { // F
38 { 0, 2, 6, 3, 4, 1, 5, 7, 8, 14, 10, 11, 12, 9, 17, 15, 16, 13, 18, 19, 20, 21,
39 22, 23, 24, 25 },
40 { 0, 2, 1, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0,
41 0 },
42 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
43 22, 23, 24, 25 },
44 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45 0 },
46 { 0, 0, 0, 0, 0, 0 } },
47 { // R
48 { 1, 5, 2, 3, 0, 4, 6, 7, 13, 9, 10, 11, 8, 16, 14, 15, 12, 17, 18, 19, 20, 21,
49 22, 23, 24, 25 },
50 { 2, 1, 0, 0, 1, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0,
51 0 },
52 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
53 22, 23, 24, 25 },
54 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 0 },
56 { 0, 0, 0, 0, 0, 0 } },
57 { // D
58 { 0, 1, 2, 3, 5, 6, 7, 4, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 16, 20, 21,
59 22, 23, 24, 25 },
60 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
61 0 },
62 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
63 22, 23, 24, 25 },
64 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 0 },
66 { 0, 0, 0, 0, 0, 0 } },

Pagina 169 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

67 { // B
68 { 4, 1, 2, 0, 7, 5, 6, 3, 8, 9, 10, 12, 19, 13, 14, 11, 16, 17, 18, 15, 20, 21,
69 22, 23, 24, 25 },
70 { 1, 0, 0, 2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 3 },
72 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
73 22, 23, 24, 25 },
74 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 0 },
76 { 0, 0, 0, 0, 0, 0 } },
77 { // Lc
78 { 4, 0, 3, 7, 5, 1, 2, 6, 12, 11, 15, 19, 16, 8, 10, 18, 13, 9, 14, 17, 20, 25,
79 21, 23, 22, 24 },
80 { 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
81 0 },
82 { 1, 5, 6, 2, 0, 4, 7, 3, 13, 17, 14, 9, 8, 16, 18, 10, 12, 19, 15, 11, 20, 21,
83 22, 23, 24, 25 },
84 { 1, 2, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
85 0 },
86 { 3, 2, 0, 1, 0, 2 } },
87 { // Uc
88 { 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, 12, 13, 14, 19, 16, 17, 18, 22, 21,
89 23, 25, 24, 20 },
90 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0 },
92 { 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12, 17, 18, 19, 16, 20, 21,
93 22, 23, 24, 25 },
94 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95 0 },
96 { 0, 3, 0, 0, 1, 0 } },
97 { // Fc
98 { 3, 2, 6, 7, 0, 1, 5, 4, 10, 14, 18, 15, 11, 9, 17, 19, 8, 13, 16, 12, 24, 20,
99 22, 21, 23, 25 },
100 { 1, 2, 1, 2, 2, 1, 2, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0,
101 0 },
102 { 4, 5, 1, 0, 7, 6, 2, 3, 16, 13, 8, 12, 19, 17, 9, 11, 18, 14, 10, 15, 20, 21,
103 22, 23, 24, 25 },
104 { 2, 1, 2, 1, 1, 2, 1, 2, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0,
105 0 },
106 { 3, 3, 3, 3, 3, 1 } } };
107
108 /*
109 * There are 54 facelets. In instellingen wordt dezelfde kleurlogica gebruikt
110 * als hier. 0 till 8 = red 9 till 17 = blue 18 till 26 = yellow 27 till 35 =
111 * orange 36 till 44 = green 45 till 53 = white
112 */
113
114 public int faceletColor[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
115 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
116 5, 5, 5, 5, 5, 5, 5 };
117 public int faceletOri[] = new int[54];
118
119 public static int faceletOriDiff[] = { 0, 0, 1, 3, 0, 1, 3, 2, 2, 0, 0, 1, 3, 0, 1, 3,
120 2, 2, 0, 0, 1, 3, 0, 1, 3, 2, 2, 0, 0, 1, 3, 0, 1, 3, 2, 2, 0, 0, 1, 3, 0, 1, 3, 2,
121 2, 0, 0, 1, 3, 0, 1, 3, 2, 2 };
122
123 public static int cubeletColors[][] = { // Default colors mapped to the
124 // cubelet.
125 { 1, 5, 3 }, { 1, 3, 2 }, { 1, 2, 0 }, { 1, 0, 5 }, // Corner-cubelets
126 { 4, 3, 5 }, { 4, 2, 3 }, { 4, 0, 2 }, { 4, 5, 0 }, // Corner-cubelets
127 { 1, 3, -1 }, { 1, 2, -1 }, { 1, 0, -1 }, { 1, 5, -1 }, // Edge-cubelets
128 { 3, 5, -1 }, { 3, 2, -1 }, { 0, 2, -1 }, { 0, 5, -1 }, // Edge-cubelets
129 { 4, 3, -1 }, { 4, 2, -1 }, { 4, 0, -1 }, { 4, 5, -1 }, // Edge-cubelets
130 { 0, -1, -1 }, { 1, -1, -1 }, { 2, -1, -1 }, { 3, -1, -1 }, { 4, -1, -1 },
131 { 5, -1, -1 } // Middle-cubelets
132 };

Pagina 170 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

133
134 public static int cubelet2facelet[][] = { { 11, 45, 29 }, { 17, 27, 20 }, { 15, 18, 2 },
135 { 9, 0, 47 }, // Elke Cubelet krijgt in welbepaalde volgorde zijn facelets
136 // toegewezen.
137 { 44, 35, 51 }, { 38, 26, 33 }, { 36, 8, 24 }, { 42, 53, 6 }, { 14, 28, -1 },
138 { 16, 19, -1 }, { 12, 1, -1 }, { 10, 46, -1 }, { 32, 48, -1 }, { 30, 23, -1 },
139 { 5, 21, -1 }, { 3, 50, -1 }, { 41, 34, -1 }, { 37, 25, -1 }, { 39, 7, -1 },
140 { 43, 52, -1 }, { 4, -1, -1 }, { 13, -1, -1 }, { 22, -1, -1 }, { 31, -1, -1 },
141 { 40, -1, -1 }, { 49, -1, -1 } };
142
143 public CubePosition() {
144 // internal general cube representation
145 // Note that the last six are not really the centres. They actually indicate
146 // the
147 // colours used on the sides of the whole cube, and also of the other
148 // pieces. A
149 // permutation of them is hence a recolouring, not a spot pattern. Their
150 // orientation is given and used in supergroup solves (0 is solved ori).
151 // Genummerd van 0-> 25 = 26 blokjes (vanbinnen hoeft er geen voorgesteld te
152 // worden).
153 // Door de volgorde van de getallen in cubeletPerm, kan men blokjes op de
154 // kubus gaan verwisselen, de laatste 6 getallen komen overeen met
155 // kleurverandering.
156
157 int[] tempCubeletPerm = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
158 17, 18, 19, 20, 21, 22, 23, 24, 25 };
159
160 // Door hier een getal in te geven kan men een blokje ter plaatse roteren.
161
162 int[] tempCubeletOri = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
163 0, 0, 0, 0, 0, 0 };
164
165 // This is fixed orientation the supergroup markers are supposed to have,
166 // relative to the initial fixed choice made. Is used to adjust markers when
167 // cube turned
168 // and relabeled.
169 // Supergroupmarkers zijn die zwarte u-tjes die er kunnen bijkomen, om ook
170 // de orientatie van de middelste blokjes consistent juist te krijgen. Je
171 // kunt een checkbox aanvinken in de solvers om die supergroups zichtbaar te
172 // maken.
173
174 int[] tempFaceOri = { 0, 0, 0, 0, 0, 0 };
175
176 this.cubeletPerm = tempCubeletPerm;
177 this.cubeletOri = tempCubeletOri;
178 this.faceOri = tempFaceOri;
179
180 }
181
182 public CubePosition(int[] tempCubeletPerm, int[] tempCubeletOri, int[] tempFaceOri) {
183 this.cubeletPerm = tempCubeletPerm;
184 this.cubeletOri = tempCubeletOri;
185 this.faceOri = tempFaceOri;
186 }
187
188 // reset routines
189 // reset to start position
190 // note: does not reset the centre colours =middle pieces or their default
191 // markings
192 public void reset() {
193 int j;
194 for (j = 0; j < 20; j++) {
195 cubeletPerm[j] = j;
196 cubeletOri[j] = 0;
197 }
198 for (j = 0; j < 6; j++) {

Pagina 171 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

199 cubeletOri[j + 20] = 0;


200 }
201 }
202
203 // reset cube orientation
204 // reorients the cube so that all their default markings line up
205 public void resetView() {
206 while (faceOri[1] != 0)
207 doMove(7);
208 if (faceOri[0] == 1 || faceOri[0] == 3)
209 doMove(6);
210 else if (faceOri[0] == 2) {
211 doMove(6);
212 doMove(6);
213 }
214
215 while (faceOri[1] != 0)
216 doMove(7);
217 }
218
219 // --- move routines ---
220 // m=0-5, normal turn
221 // m=6-8, middle layer turn
222 // m=9-11, cube turn
223 // m=12-14, slice move
224 // m=15-17, anti-slice move
225 // q=+/-1 or +-2.
226 public void doMove(int m, int q, boolean allowRot) {
227 if (q < 0)
228 q += 4;
229 while (q > 0) {
230 if (m >= 15) { // anti-slice
231 doMove(m - 15);
232 doMove(m - 12);
233 } else if (m >= 12) { // slice
234 doMove(m - 12);
235 doMove(m - 9);
236 doMove(m - 9);
237 doMove(m - 9);
238 } else if (m >= 9) { // cube turn
239 if (allowRot)
240 doMove(m - 3);
241 } else if (m >= 6) { // middle slice turn
242 if (allowRot)
243 doMove(m); // turn whole cube
244 doMove(m - 3); // far side back
245 doMove(m - 6);
246 doMove(m - 6);
247 doMove(m - 6); // near side back
248 } else { // normal face turn
249 doMove(m);
250 }
251 q--;
252 }
253 }
254
255 public void doMove(int m) {
256 doMove(m, cubeletPerm, cubeletOri, faceOri);
257 }
258
259 void doMove(int m, int[] p0, int[] o0, int[] f0) {
260 // m=0..8, does single quarter turn of relevant face, or whole cube
261 int i;
262 int[] perm = new int[26], ori = new int[26], fc = new int[6];
263
264 for (i = 0; i < 26; i++) {

Pagina 172 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

265 // do permutation
266 perm[i] = p0[movePerm[m][0][i]];
267 ori[i] = o0[movePerm[m][0][i]];
268 if (ori[i] >= 0)
269 ori[i] += movePerm[m][1][i];
270 // relabel pieces - reorient cube
271 if (perm[i] >= 0) {
272 perm[i] = movePerm[m][2][perm[i]];
273 if (ori[i] >= 0)
274 ori[i] += movePerm[m][3][perm[i]];
275 }
276 if (ori[i] >= 0) {
277 if (i < 8) {
278 while (ori[i] > 2)
279 ori[i] -= 3; // Van de cornerCubelets wordt er van de orientatie 3
280 // afgetrokken tot de orientatie 0, 1 of 2 beterft.
281 } else if (i < 20) {
282 while (ori[i] > 1)
283 ori[i] -= 2; // Van de edgeCubelets wordt er van de orientatie 2
284 // afgetroeken tot de orienatatie 0 of 1 is.
285 } else {
286 while (ori[i] > 3)
287 ori[i] -= 4; // Van de middleCubelets, stelt de oriëntatie -4
288 // dezelfde oriëntatie voor.
289 }
290 }
291 }
292 for (i = 0; i < 6; i++) {
293 // Permute and adjust face base orientations
294 fc[i] = f0[movePerm[m][0][i + 20] - 20] + movePerm[m][4][i];
295 while (fc[i] > 3)
296 fc[i] -= 4;
297 }
298 // copy new position to current
299 for (i = 0; i < 26; i++) {
300 p0[i] = perm[i];
301 o0[i] = ori[i];
302 }
303 for (i = 0; i < 6; i++) {
304 f0[i] = fc[i];
305 }
306 }
307
308 public void doSequence(MoveSequence ms) {
309 doSequence(ms, ms.getLength());
310 }
311
312 public void doSequence(MoveSequence ms, int l) {
313 int i;
314 reset();
315 for (i = 0; i < l; i++) {
316 doMove(ms.getMoves()[i], ms.getAmount()[i], true);
317 }
318 }
319
320 public void editMove(int c1, int o1, int c2, int o2) {
321 int i;
322 if (c1 < 8 && c2 < 8) {
323 // swap corners
324 if (c1 == c2) {
325 // change orientation of piece c1;
326 cubeletOri[c1] += o1 + 3 - o2;
327 while (cubeletOri[c1] > 2)
328 cubeletOri[c1] -= 3;
329 } else {
330 i = cubeletPerm[c1];

Pagina 173 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

331 cubeletPerm[c1] = cubeletPerm[c2];


332 cubeletPerm[c2] = i;
333 i = cubeletOri[c1];
334 cubeletOri[c1] = cubeletOri[c2];
335 cubeletOri[c2] = i;
336 cubeletOri[c1] += o2 + 3 - o1;
337 cubeletOri[c2] += o1 + 3 - o2;
338 while (cubeletOri[c1] > 2)
339 cubeletOri[c1] -= 3;
340 while (cubeletOri[c2] > 2)
341 cubeletOri[c2] -= 3;
342 }
343 } else if (c1 >= 8 && c2 >= 8 && c1 < 20 && c2 < 20) {
344 // swap edges
345 if (c1 == c2) {
346 // change orientation of piece c1;
347 cubeletOri[c1] += o2 + o1;
348 while (cubeletOri[c1] > 1)
349 cubeletOri[c1] -= 2;
350 } else {
351 i = cubeletPerm[c1];
352 cubeletPerm[c1] = cubeletPerm[c2];
353 cubeletPerm[c2] = i;
354 i = cubeletOri[c1];
355 cubeletOri[c1] = cubeletOri[c2];
356 cubeletOri[c2] = i;
357 cubeletOri[c1] += o2 + o1;
358 cubeletOri[c2] += o1 + o2;
359 while (cubeletOri[c1] > 1)
360 cubeletOri[c1] -= 2;
361 while (cubeletOri[c2] > 1)
362 cubeletOri[c2] -= 2;
363 }
364 } else if (c1 >= 20 && c2 >= 20) {
365 // swap centres
366 if (c1 == c2) {
367 // change orientation of piece c1;
368 if (cubeletOri[c1] <= 0)
369 cubeletOri[c1] = 3;
370 else
371 cubeletOri[c1]--;
372 } else {
373 i = cubeletPerm[c1];
374 cubeletPerm[c1] = cubeletPerm[c2];
375 cubeletPerm[c2] = i;
376 i = cubeletOri[c1];
377 cubeletOri[c1] = cubeletOri[c2];
378 cubeletOri[c2] = i;
379 }
380 }
381 }
382
383 void doReflect(int[] p0, int[] o0, int[] f0) {
384 final int refPerm[] = {
385 // piece perm/ori, relabel perm/ori, color perm
386 6, 7, 4, 5, 2, 3, 0, 1, 18, 19, 16, 17, 14, 15, 12, 13, 10, 11, 8, 9, 23, 24, 25,
387 20, 21, 22, };
388
389 int i;
390 int[] perm = new int[26], ori = new int[26], fc = new int[6];
391
392 for (i = 0; i < 26; i++) {
393 // do permutation, swapping opposite pieces
394 perm[i] = p0[refPerm[i]];
395 ori[i] = o0[refPerm[i]];
396 // reverse its orientation

Pagina 174 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

397 if (ori[i] > 0) {


398 if (i < 8)
399 ori[i] ^= 3;
400 else if (i >= 20)
401 ori[i] = 4 - ori[i];
402 }
403
404 // relabel pieces to their opposites
405 if (i < 20 && perm[i] >= 0)
406 perm[i] = refPerm[perm[i]];
407 }
408 for (i = 0; i < 6; i++) {
409 // swap & mirror opposite base orientations
410 fc[i] = 4 - f0[refPerm[i + 20] - 20];
411 if (i != 1 && i != 4)
412 fc[i] ^= 2;
413 }
414
415 // copy new position to current
416 for (i = 0; i < 26; i++) {
417 p0[i] = perm[i];
418 o0[i] = ori[i];
419 }
420 // copy new face base orientations
421 for (i = 0; i < 6; i++)
422 f0[i] = fc[i];
423 }
424
425 public void doSym(int m, boolean fixCentres) {
426 if (fixCentres) {
427 int saveCentres[] = new int[6];
428 for (int i = 0; i < 6; i++)
429 saveCentres[i] = cubeletPerm[20 + i];
430 doSym(m, cubeletPerm, cubeletOri, faceOri);
431 for (int i = 0; i < 6; i++)
432 cubeletPerm[20 + i] = saveCentres[i];
433 } else {
434 doSym(m, cubeletPerm, cubeletOri, faceOri);
435 }
436 }
437
438 void doSym(int m, int[] p0, int[] o0, int[] f0) {
439 // m=0..28, does relevant reflection/rotation
440 switch (m) {
441 case 0:
442 doReflect(p0, o0, f0);
443 break;
444 case 1:
445 case 2:
446 case 3:
447 doSym(26 + (m - 1), p0, o0, f0);
448 doReflect(p0, o0, f0);
449 break;
450 case 4:
451 case 5:
452 case 6:
453 doSym(23 + (m - 4), p0, o0, f0);
454 doReflect(p0, o0, f0);
455 break;
456 case 7:
457 case 8:
458 case 9:
459 case 10:
460 case 11:
461 case 12:
462 doSym(13 + (m - 7), p0, o0, f0);

Pagina 175 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

463 doReflect(p0, o0, f0);


464 break;
465
466 case 13:
467 case 14:
468 case 15:
469 doSym(16 + (m - 13), p0, o0, f0);
470 doSym(16 + (m - 13), p0, o0, f0);
471 break;
472 case 16:
473 doMove(7, p0, o0, f0);
474 break;
475 case 17:
476 doMove(6, p0, o0, f0);
477 doMove(6, p0, o0, f0);
478 doMove(6, p0, o0, f0);
479 break;
480 case 18:
481 doMove(8, p0, o0, f0);
482 break;
483
484 case 19:
485 doMove(6, p0, o0, f0);
486 doMove(7, p0, o0, f0);
487 break;
488 case 20:
489 doMove(7, p0, o0, f0);
490 doMove(6, p0, o0, f0);
491 break;
492 case 21:
493 doMove(7, p0, o0, f0);
494 doSym(17, p0, o0, f0);
495 break;
496 case 22:
497 doMove(7, p0, o0, f0);
498 doMove(8, p0, o0, f0);
499 break;
500
501 case 23:
502 doSym(22, p0, o0, f0);
503 doMove(8, p0, o0, f0);
504 break;
505 case 24:
506 doSym(20, p0, o0, f0);
507 doMove(8, p0, o0, f0);
508 break;
509 case 25:
510 doSym(22, p0, o0, f0);
511 doSym(17, p0, o0, f0);
512 break;
513
514 case 26:
515 doSym(21, p0, o0, f0);
516 doSym(17, p0, o0, f0);
517 break;
518 case 27:
519 doSym(19, p0, o0, f0);
520 doMove(7, p0, o0, f0);
521 break;
522 case 28:
523 doSym(20, p0, o0, f0);
524 doMove(7, p0, o0, f0);
525 break;
526 }
527 }
528

Pagina 176 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

529 public int getSym() {


530 int t = 0, m = 1;
531 for (int i = 0; i < 29; i++) {
532 if (checkSym(i))
533 t |= m;
534 m <<= 1;
535 }
536 return (t);
537 }
538
539 boolean checkSym(int m) {
540 int i;
541 int[] p = new int[26], o = new int[26], f = new int[6];
542
543 for (i = 0; i < 26; i++) {
544 p[i] = cubeletPerm[i];
545 o[i] = cubeletOri[i];
546 }
547 for (i = 0; i < 6; i++)
548 f[i] = faceOri[i];
549 doSym(m, p, o, f);
550 boolean ret = true;
551 for (i = 0; i < 20 && ret; i++) {
552 ret &= (p[i] == cubeletPerm[i]) && (o[i] == cubeletOri[i]);
553 }
554 return ret;
555 }
556
557 public void mix(int t, boolean centres, boolean twoCol) {
558 int[] p0 = new int[26], o0 = new int[26], f0 = new int[6];
559 int i;
560 for (i = 0; i < 20; i++)
561 p0[i] = o0[i] = -1;
562 for (i = 20; i < 26; i++) {
563 f0[i - 20] = -1;
564 p0[i] = i;
565 o0[i] = centres ? -1 : 0;
566 }
567
568 if (mixRest(0, p0, o0, f0, t, centres, twoCol, false)) {
569 for (i = 0; i < 26; i++) {
570 if (i < 20)
571 cubeletPerm[i] = p0[i];
572 cubeletOri[i] = o0[i];
573 }
574 } else {
575 System.out.println("Programming error - no mixed position found");
576 }
577 }
578
579 boolean mixRest(int pt, int[] p0, int[] o0, int[] f0, int t, boolean centres,
580 boolean twoCol, boolean doOri) {
581 int i, j, fs, ll;
582 int[] lst;
583
584 // save a copy of position
585 int[] p1 = new int[26];
586 int[] o1 = new int[26];
587 for (i = 0; i < 26; i++) {
588 p1[i] = p0[i];
589 o1[i] = o0[i];
590 }
591
592 // check current position can be extended to right symmetry
593 if (testSym(p0, o0, f0, t, centres, twoCol)) {
594

Pagina 177 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

595 // find first slot


596 for (fs = pceTypes[pt]; fs < pceTypes[pt + 1]
597 && ((!doOri && p0[fs] >= 0) || (doOri && o0[fs] >= 0)); fs++)
598 ;
599 if (fs >= pceTypes[pt + 1]) {
600 if (!doOri)
601 pt += 3;
602 if (pt >= pceTypes.length || mixRest(pt, p0, o0, f0, t, centres, twoCol, doOri))
603 return true;
604 } else {
605 // make list of all available options for the empty slot
606 ll = 0;
607 if (doOri) {
608 lst = new int[pceTypes[pt + 2]];
609 for (i = 0; i < pceTypes[pt + 2]; i++)
610 lst[ll++] = i;
611 } else {
612 lst = new int[12];
613 // build full list and...
614 for (i = pceTypes[pt]; i < pceTypes[pt + 1]; i++)
615 lst[ll++] = i;
616 // ...remove used pieces
617 for (i = pceTypes[pt]; i < pceTypes[pt + 1]; i++) {
618 if (p0[i] >= 0) {
619 for (j = 0; j < ll && lst[j] != p0[i]; j++)
620 ;
621 lst[j] = lst[ll - 1];
622 ll--;
623 }
624 }
625 }
626
627 // try each piece
628 while (ll > 0) {
629 // choose random piece
630 i = (int) (ll * Math.random());
631 if (doOri) {
632 o0[fs] = lst[i];
633 } else {
634 p0[fs] = lst[i];
635 }
636 // try to complete mix
637 if (mixRest(pt, p0, o0, f0, t, centres, twoCol, !doOri))
638 return true;
639 // failed, remove piece from list
640 ll--;
641 lst[i] = lst[ll];
642 }
643 }
644 }
645
646 // all fails. restore position
647 for (i = 0; i < 26; i++) {
648 p0[i] = p1[i];
649 o0[i] = o1[i];
650 }
651 return false;
652 }
653
654 boolean testSym(int[] p0, int[] o0, int[] f0, int t0, boolean centres, boolean twoCol) {
655 int[] p1 = new int[26], o1 = new int[26];
656 int i, j, k;
657 boolean tryAgain;
658 do {
659 tryAgain = false;
660 for (i = 0; i < 29; i++) {

Pagina 178 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

661 if ((t0 & (1 << i)) != 0) {


662 // make copy
663 for (j = 0; j < 26; j++) {
664 p1[j] = p0[j];
665 o1[j] = o0[j];
666 }
667 // apply symmetry to one of them
668 doSym(i, p0, o0, f0);
669 // merge the two / check compatible
670 for (j = 0; j < 26; j++) {
671 if (p0[j] >= 0) {
672 if (p1[j] >= 0 && p1[j] != p0[j] && j < 20) {
673 // conflict
674 return false;
675 }
676 } else if (p1[j] >= 0) {
677 // merge it
678 p0[j] = p1[j];
679 tryAgain = true;
680 }
681 if (o0[j] >= 0) {
682 if (o1[j] >= 0 && o1[j] != o0[j]) {
683 // conflict
684 return false;
685 }
686 } else if (o1[j] >= 0) {
687 // merge it
688 o0[j] = o1[j];
689 tryAgain = true;
690 }
691 }
692 }
693 }
694 } while (tryAgain);
695 // position has right symmetry, but check if it is valid position
696 // first check for duplicate pieces
697 for (i = 0; i < 20; i++) {
698 if (p0[i] >= 0) {
699 for (j = i + 1; j < 20; j++) {
700 if (p0[i] == p0[j])
701 return false;
702 }
703 }
704 }
705 // now check corner orientation
706 j = 0;
707 for (i = 0; i < 8 && o0[i] >= 0; i++)
708 j += o0[i];
709 if (i >= 8 && (j % 3) != 0)
710 return false;
711
712 // now check edge orientation
713 j = 0;
714 for (i = 8; i < 20 && o0[i] >= 0; i++)
715 j += o0[i];
716 if (i >= 20 && (j & 1) != 0)
717 return false;
718
719 // check piece parity
720 tryAgain = false;
721 for (i = 0; i < 20; i++) {
722 if (p0[i] < 0)
723 break;
724 for (j = i + 1; j < 20; j++) {
725 if (p0[j] < p0[i])
726 tryAgain = !tryAgain;

Pagina 179 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

727 }
728 }
729 if (i >= 20 && tryAgain)
730 return false;
731
732 // now check center orientation
733 // first get corner parity
734 if (centres) {
735 tryAgain = false;
736 for (i = 0; i < 8; i++) {
737 for (j = i + 1; j < 8; j++) {
738 if (p0[j] < p0[i])
739 tryAgain = !tryAgain;
740 }
741 }
742 for (i = 20; i < 26 && o0[i] >= 0; i++)
743 if ((o0[i] & 1) != 0)
744 tryAgain = !tryAgain;
745 if (i >= 26 && tryAgain)
746 return false;
747 }
748
749 // finally check for two colours per face
750 if (twoCol) {
751 int[] fc = new int[54], fo = new int[54];
752 getFaceletColors(p0, o0, f0, fc, fo);
753 // check each face
754 int[] lst = new int[7];
755 int ll;
756 for (i = 0; i < 54; i += 9) {
757 ll = 0;
758 for (j = i; j < i + 9; j++) {
759 if (fc[j] >= 0) {
760 for (k = 0; k < ll && lst[k] != fc[j]; k++)
761 ;
762 if (k >= ll)
763 lst[ll++] = fc[j];
764 }
765 }
766 if (ll > 2)
767 return false;
768 }
769 }
770 return true;
771 }
772
773 // convert internal cube representation to cube facelets colours
774 // and facelet marking orientation
775 public void getFaceletColors() {
776 getFaceletColors(cubeletPerm, cubeletOri, faceOri, faceletColor, faceletOri);
777 }
778
779 public void getFaceletColors(int[] p0, int[] o0, int[] f0, int[] fc, int[] fo) {
780 int i, j, k, o, c;
781
782 for (i = 0; i < 54; i++) {
783 fc[i] = -1;
784 } // In het totaal zijn er 54 facelets.
785 for (i = 0; i < 20; i++) { // Alle niet-middenste cubelets overlopen.
786 // get cubelet that is in position i
787 k = p0[i];
788 o = o0[i];
789 if (k >= 0 && o >= 0) {
790
791 for (j = 0; j < 3 && (j < 2 || i < 8); j++) {
792 // i is kleiner dan 8 zolang het over cornercubelets gaat.

Pagina 180 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubePosition

793 // Als j 3 dreigt te worden, dan stopt de lus zeker. Als j=2 dreigt te
794 // worden of i 8
795 // dan stopt hij ook denk ik.
796
797 // get facelet color on each side
798 c = cubeletColors[k][o];
799 // color the correct cube facelet
800 fc[cubelet2facelet[i][j]] = c;
801
802 // get the orientation the facelet has in its home position
803 c = f0[c];
804 // adjust by movement to current position
805 c += faceletOriDiff[cubelet2facelet[k][o]]
806 - faceletOriDiff[cubelet2facelet[i][j]];
807 c &= 3;
808 // save the facelet orientation
809 fo[cubelet2facelet[i][j]] = c;
810
811 o = (o == 2 || (o == 1 && i >= 8)) ? 0 : o + 1;
812 }
813 }
814 }
815 for (i = 20; i < 26; i++) {
816 // get cubelet that is in position i
817 o = o0[i];
818
819 // color the centre facelet
820 fc[cubelet2facelet[i][0]] = i - 20;
821 if (o >= 0) {
822 // get the orientation the facelet should have
823 c = f0[i - 20];
824 // adjust by current orientation
825 c += o;
826 c &= 3;
827 // save the facelet orientation
828 fo[cubelet2facelet[i][0]] = c;
829 }
830 }
831 }
832 }

Pagina 181 van 329 CubeThesis™ Depamelaere-Deschuytter


class CubieSettings

1 package solver.solverJS.algorithm;
2
3 public final class CubieSettings {
4 public int group = 0; // current cube group
5 public boolean superGroup = false; // set if centre orientation visible
6 public boolean solving = false; // set while some solver is busy
7 public volatile int lastOutputSolver = -1; //
8 public MoveSequence generator = null; // movesequence returned from solver
9 public boolean edit = false; // set when edit mode, else play mode.
10
11 public boolean lockViewer = false; // set by cubie to disable user interaction
12 // on viewer
13 // current cube position
14 public CubePosition cubePos = new CubePosition();
15 }

Pagina 182 van 329 CubeThesis™ Depamelaere-Deschuytter


class MoveSequence

1 package solver.solverJS.algorithm;
2
3 public final class MoveSequence {
4 int len;
5 int moves[];
6 int amount[];
7
8 public MoveSequence() {
9 }
10
11 public MoveSequence(int l, int mvs[], int amt[]) {
12 // given a solution, create generating move sequence
13 int i;
14 len = l;
15 moves = new int[len];
16 amount = new int[len];
17 for (i = 0; i < l; i++) {
18 amount[i] = 4 - amt[l - 1 - i];
19 moves[i] = mvs[l - 1 - i];
20 }
21 simplify();
22 }
23
24 public int[] getMoves() {
25 return (moves);
26 }
27
28 public int[] getAmount() {
29 return (amount);
30 }
31
32 public int getLength() {
33 return (len);
34 }
35
36 public void setMoveSeqFromCBTH(int l, int mvs[], int amt[]) {
37 len = l;
38 moves = mvs;
39 amount = amt;
40 }
41
42 // m=0-5, normal turn
43 // m=6-8, middle layer turn
44 // m=9-11, cube turn
45 // m=12-14, slice move
46 // m=15-17, anti-slice move
47
48 public String toString(boolean inverse) {
49 return (toString(inverse, -1));
50 }
51
52 public String toString(boolean inverse, int pos) {
53 int i, j, m, di, qtm = 0, ftm = 0, stm = 0, q; // qtm = quartermove stm =
54 // slice move
55 StringBuffer sol = new StringBuffer();
56 if (len == 0)
57 return ("");
58 if (inverse) {
59 i = len - 1;
60 di = -1; // di= 'delta i', the sense of incrementation through the
61 // solution.
62 } else {
63 i = 0;
64 di = 1;
65 }
66

Pagina 183 van 329 CubeThesis™ Depamelaere-Deschuytter


class MoveSequence

67 // Print an additional space so generation/solutionbar doesn't jump:


68 if ((pos != len && di < 0) || (pos != 0 && di > 0)) {
69 sol.append(" ");
70 }
71
72 while (i >= 0 && i < len) {
73
74 if ((i == pos && di > 0) || (i + 1 == pos && di < 0)) {
75 sol.append("\u25CF");
76 }
77
78 q = amount[i];
79 m = moves[i];
80 if (inverse)
81 q = 4 - q;
82 if (m < 6) {
83 sol.append("LUFRDB".charAt(m));
84 j = 1;
85 } else {
86 sol.append("LUF".charAt(m % 3));
87 sol.append("xxmcsa".charAt(m / 3));
88 j = (m < 9 || m > 11) ? 2 : 0; // j=#faces moved
89 }
90 if (q > 1) {
91 sol.append("2'".charAt(q - 2));
92 }
93 if (q == 2) {
94 qtm += j;
95 }
96 qtm += j;
97 ftm += j;
98 if (j != 0)
99 stm++;
100 i += di;
101 if (!(i == pos && di > 0 || (i + 1 == pos && di < 0))) {
102 sol.append(" ");
103 }
104 }
105 if ((pos == len && di > 0) || (pos == 0 && di < 0)) {
106 sol.append("\u25CF");
107 }
108 if (qtm != 0) {
109 sol.append("(" + ftm);
110 if (ftm != qtm)
111 sol.append("," + qtm + "q");
112 if (stm != ftm)
113 sol.append("," + stm + "s");
114 sol.append(")");
115 }
116 return (sol.toString());
117 }
118
119 public void parse(String inp, boolean inverse) {
120 // moves parsed so far
121 int mv[] = new int[80];
122 int am[] = new int[80];
123 int ln = 0;
124
125 int c, m = -1, q = -1, t = -1, i = 0, p = 0;
126 while ((i != 0 || p < inp.length()) && ln < 80) {
127 // get next character
128 if (p < inp.length())
129 c = inp.charAt(p);
130 else
131 c = 0;
132 if (i == 0) { // parse next move

Pagina 184 van 329 CubeThesis™ Depamelaere-Deschuytter


class MoveSequence

133 p++;
134 m = "LUFRDBTlufrdbt".indexOf(c);
135 if (m < 0)
136 continue; // ignore bogus character
137 if (m > 6)
138 m -= 7;
139 if (m == 6)
140 m = 1;
141 i++;
142 } else if (i == 1) { // parse type
143 t = "mcsaMCSA".indexOf(c);
144 if (t >= 4)
145 t -= 4;
146 if (t >= 0)
147 p++; // found type character, skip it.
148 i++;
149 } else if (i == 2) {
150 q = "1+23'-".indexOf(c);
151 if (q >= 0)
152 p++;
153 else
154 q = 1;
155 if (q > 3)
156 q = 3;
157 else if (q <= 1)
158 q = 1;
159
160 // choose canonical face (LUF) in abnormal moves
161 if (t >= 0 && m > 2) {
162 m -= 3;
163 if (t != 3)
164 q = 4 - q;
165 }
166 // append move to list
167 mv[ln] = (t < 0) ? m : m + 6 + 3 * t;
168 am[ln] = q;
169 ln++;
170 i = 0;
171 }
172 }
173
174 // save result
175 len = ln;
176 moves = new int[ln];
177 amount = new int[ln];
178 for (i = 0; i < ln; i++) {
179 moves[i] = mv[i];
180 amount[i] = am[i];
181 }
182
183 simplify();
184
185 if (inverse) {
186 // invert whole sequence
187 for (i = 0, t = len - 1; i < t; i++, t--) {
188 q = moves[i];
189 moves[i] = moves[t];
190 moves[t] = q;
191 q = amount[i];
192 amount[i] = 4 - amount[t];
193 amount[t] = 4 - q;
194 }
195 if (i == t)
196 amount[i] = 4 - amount[i];
197 }
198 }

Pagina 185 van 329 CubeThesis™ Depamelaere-Deschuytter


class MoveSequence

199
200 private void simplify() {
201 int axis[] = new int[len];
202 int type[] = new int[len];
203 int i, j, k;
204 int turns[] = new int[3];
205 // create list of axes/movetypes
206 for (i = 0; i < len; i++) {
207 axis[i] = moves[i] % 3;
208 type[i] = (moves[i] - axis[i]) / 3;
209 }
210
211 // do simplification on each move
212 i = 0;
213 while (i < len) {
214 // collect moves on same axis as current move
215 turns[0] = turns[1] = turns[2] = 0;
216 for (j = i; j < len && axis[i] == axis[j]; j++) {
217 switch (type[j]) {
218 case 0: // normal, near face
219 turns[0] += amount[j];
220 break;
221 case 1: // normal, far face
222 turns[2] += amount[j];
223 break;
224 case 2: // mid slice
225 turns[1] += amount[j];
226 break;
227 case 3: // whole cube
228 turns[0] += amount[j];
229 turns[1] += amount[j];
230 turns[2] -= amount[j];
231 break;
232 case 4: // slice move
233 turns[0] += amount[j];
234 turns[2] -= amount[j];
235 break;
236 case 5: // anti-slice move
237 turns[0] += amount[j];
238 turns[2] += amount[j];
239 break;
240 }
241 }
242
243 // only one move on this axis, so just leave it
244 if (j <= i + 1) {
245 i++;
246 continue;
247 }
248
249 // simplify
250 turns[0] &= 3;
251 turns[1] &= 3;
252 turns[2] &= 3;
253 if (turns[0] == 0 && turns[1] == 0 && turns[2] == 0) {
254 // annihilation, ok
255 } else if (turns[0] == turns[1] && turns[0] + turns[2] == 4) {
256 // cube turn, ok
257 amount[i] = turns[0];
258 type[i] = 3;
259 moves[i] = 9 + axis[i];
260 i++;
261 } else if (turns[1] == 0 && turns[2] == 0) {
262 // normal, near face, ok
263 amount[i] = turns[0];
264 type[i] = 0;

Pagina 186 van 329 CubeThesis™ Depamelaere-Deschuytter


class MoveSequence

265 moves[i] = axis[i];


266 i++;
267 } else if (turns[0] == 0 && turns[1] == 0) {
268 // normal, far face, ok
269 amount[i] = turns[2];
270 type[i] = 1;
271 moves[i] = 3 + axis[i];
272 i++;
273 } else if (turns[0] == 0 && turns[2] == 0) {
274 // middle slice, ok
275 amount[i] = turns[1];
276 type[i] = 2;
277 moves[i] = 6 + axis[i];
278 i++;
279 } else if (turns[1] == 0 && turns[0] + turns[2] == 4) {
280 // slice turn, ok
281 amount[i] = turns[0];
282 type[i] = 4;
283 moves[i] = 12 + axis[i];
284 i++;
285 } else if (turns[1] == 0 && turns[0] == turns[2]) {
286 // anti-slice turn, ok
287 amount[i] = turns[0];
288 type[i] = 5;
289 moves[i] = 15 + axis[i];
290 i++;
291 } else if (turns[0] == turns[1]) {
292 // cube + far face, ok
293 // cube turn
294 amount[i] = turns[0];
295 type[i] = 3;
296 moves[i] = 9 + axis[i];
297 i++;
298 // far
299 amount[i] = (turns[2] + turns[0]) & 3;
300 type[i] = 1;
301 moves[i] = 3 + axis[i];
302 i++;
303 } else if (turns[2] + turns[1] == 4) {
304 // cube + near face, ok
305 // cube turn
306 amount[i] = turns[1];
307 type[i] = 3;
308 moves[i] = 9 + axis[i];
309 i++;
310 // near
311 amount[i] = (turns[0] + turns[2]) & 3;
312 type[i] = 0;
313 moves[i] = axis[i];
314 i++;
315 } else if (turns[2] + turns[0] == 4) {
316 // cube + slice, ok
317 // cube turn
318 amount[i] = turns[1];
319 type[i] = 3;
320 moves[i] = 9 + axis[i];
321 i++;
322 // slice
323 amount[i] = (turns[0] - turns[1]) & 3;
324 type[i] = 4;
325 moves[i] = 12 + axis[i];
326 i++;
327 } else if (((turns[0] - 2 * turns[1] - turns[2]) & 3) == 0) {
328 // cube + anti-slice, ok
329 // cube turn
330 amount[i] = turns[1];

Pagina 187 van 329 CubeThesis™ Depamelaere-Deschuytter


class MoveSequence

331 type[i] = 3;
332 moves[i] = 9 + axis[i];
333 i++;
334 // anti-slice
335 amount[i] = (turns[0] - turns[1]) & 3;
336 type[i] = 5;
337 moves[i] = 15 + axis[i];
338 i++;
339 } else if (turns[0] == 0 || turns[1] == 0 || turns[2] == 0) {
340 // 2 layer turns
341 if (turns[0] != 0) {
342 // near
343 amount[i] = turns[0];
344 type[i] = 0;
345 moves[i] = axis[i];
346 i++;
347 }
348 if (turns[1] != 0) {
349 // middle
350 amount[i] = turns[1];
351 type[i] = 2;
352 moves[i] = 6 + axis[i];
353 i++;
354 }
355 if (turns[2] != 0) {
356 // far
357 amount[i] = turns[2];
358 type[i] = 1;
359 moves[i] = 3 + axis[i];
360 i++;
361 }
362 } else {
363 // 2 face turns + cube
364 // near
365 amount[i] = (turns[0] - turns[1]) & 3;
366 type[i] = 0;
367 moves[i] = axis[i];
368 i++;
369 // cube
370 amount[i] = turns[1];
371 type[i] = 3;
372 moves[i] = 9 + axis[i];
373 i++;
374 // far
375 amount[i] = (turns[1] + turns[2]) & 3;
376 type[i] = 1;
377 moves[i] = 3 + axis[i];
378 i++;
379 }
380
381 // remove used-up moves
382 len -= j - i;
383 for (k = i; k < len; k++) {
384 moves[k] = moves[k + j - i];
385 amount[k] = amount[k + j - i];
386 axis[k] = axis[k + j - i];
387 type[k] = type[k + j - i];
388 }
389 }
390 }
391
392 final int symPerm[][] = { { 3, 4, 5, 0, 1, 2 }, { 5, 1, 3, 2, 4, 0 },
393 { 0, 2, 1, 3, 5, 4 }, { 4, 3, 2, 1, 0, 5 }, { 2, 1, 0, 5, 4, 3 },
394 { 0, 5, 4, 3, 2, 1 }, { 1, 0, 2, 4, 3, 5 }, { 0, 4, 2, 3, 1, 5 },
395 { 3, 1, 2, 0, 4, 5 }, { 0, 1, 5, 3, 4, 2 }, { 2, 4, 3, 5, 1, 0 },
396 { 3, 2, 4, 0, 5, 1 }, { 4, 0, 5, 1, 3, 2 },

Pagina 188 van 329 CubeThesis™ Depamelaere-Deschuytter


class MoveSequence

397
398 { 3, 1, 5, 0, 4, 2 }, { 0, 4, 5, 3, 1, 2 }, { 3, 4, 2, 0, 1, 5 },
399 { 5, 1, 0, 2, 4, 3 }, { 0, 5, 1, 3, 2, 4 }, { 1, 3, 2, 4, 0, 5 },
400 { 5, 0, 4, 2, 3, 1 }, { 1, 2, 0, 4, 5, 3 }, { 4, 5, 0, 1, 2, 3 },
401 { 5, 3, 1, 2, 0, 4 }, { 5, 4, 3, 2, 1, 0 }, { 3, 2, 1, 0, 5, 4 },
402 { 4, 3, 5, 1, 0, 2 }, { 2, 4, 0, 5, 1, 3 }, { 3, 5, 4, 0, 2, 1 },
403 { 1, 0, 5, 4, 3, 2 } };
404
405 public void doSym(int s) {
406 int q, m, t;
407 for (int i = 0; i < len; i++) {
408 q = amount[i];
409 m = moves[i];
410 if (s < 13)
411 q = 4 - q;
412 if (m < 6) {
413 m = symPerm[s][m];
414 } else {
415 t = (m - 6) / 3;
416 m = m % 3;
417 m = symPerm[s][m];
418 if (m > 2) {
419 m -= 3;
420 if (t < 3)
421 q = 4 - q;
422 }
423 m = 6 + 3 * t + m;
424 }
425 amount[i] = q;
426 moves[i] = m;
427 }
428 }
429 }

Pagina 189 van 329 CubeThesis™ Depamelaere-Deschuytter


class Solver

1 // Rubik's Cube simulator


2 package solver.solverJS.algorithm;
3
4 import java.awt.event.*;
5
6 //--- Solver class, abstract. ---
7
8 public abstract class Solver implements Runnable {
9 boolean prepared = false; // flag is set when tables are prepared
10 boolean wanttostop = false; // flag is set when solver should be stopped soon
11 boolean running = false;
12
13 int sollen = 0; // number of moves in the move list
14 int solmoves[] = new int[40]; // faces of moves performed during search
15 int solamount[] = new int[40]; // exponent of moves performed during search
16 int positionlist[][]; // encoded positions
17 CubieSettings cubieSettings;
18 ActionListener main;
19
20 public Solver(ActionListener m) {
21 main = m;
22 }
23
24 public void setSettings(CubieSettings s) {
25 cubieSettings = s;
26 }
27
28 // start thread - either calc tables or solve
29 public void run() {
30 if (!prepared) {
31 init();
32 prepared = true;
33 doEvent(0);
34 } else if (!cubieSettings.solving && !wanttostop) {
35 cubieSettings.solving = true;
36 running = true;
37 doEvent(4);
38 boolean r = solve(); // do it!
39 running = false;
40 cubieSettings.solving = false;
41 if (wanttostop) {
42 wanttostop = false;
43 doEvent(2);
44 } else if (!r) {
45 doEvent(3); // Er werd geen oplossing gevonden.
46 } else {
47 // if found solution, and not interrupted
48 cubieSettings.generator = getGenerator();
49 doEvent(1);
50 }
51 }
52 }
53
54 public void stopSolving() {
55 if (running)
56 wanttostop = true;
57 }
58
59 void doEvent(int t) {
60 // Dispatch action event that solver has finished.
61 // Four event types:
62 // 0. initialisation done.
63 // 1. Solution found
64 // 2. Solver aborted by user
65 // 3. Solver finished, no solution found.
66 // I did not bother to implement an addActionListener method as there

Pagina 190 van 329 CubeThesis™ Depamelaere-Deschuytter


class Solver

67 // will only ever be one listener to this, viz the main cubie applet.
68 String cm[] = { "a", "b", "c", "d", "e" };
69 ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, cm[t]);
70 main.actionPerformed(e);
71 }
72
73 // access function prepared flag
74 public boolean isPrepared() {
75 return (prepared);
76 }
77
78 public boolean isRunning() {
79 return (running);
80 }
81
82 // Set position to be solved - initialise search if new position
83 abstract public boolean setPosition(CubePosition cubePos, boolean test);
84
85 // Start/continue search
86 abstract protected boolean solve();
87
88 // initialise tables
89 abstract protected void init();
90
91 // mix cube within this cube group
92 abstract public void mix(CubePosition cubePos);
93
94 // convert movelist into string solution
95 abstract public MoveSequence getGenerator();
96
97 // --- General utilities ---
98 protected void swap(int pr[], int i, int j) {
99 int c = pr[i];
100 pr[i] = pr[j];
101 pr[j] = c;
102 }
103
104 protected void cycle(int pr[], int i, int j, int k, int l) {
105 int c = pr[i];
106 pr[i] = pr[j];
107 pr[j] = pr[k];
108 pr[k] = pr[l];
109 pr[l] = c;
110 }
111
112 // return true if permutation is odd
113 protected boolean parityOdd(int pieces[], int start, int len) {
114 int i, j;
115 boolean p = false;
116 for (i = 0; i < len; i++) {
117 for (j = 0; j < i; j++) {
118 p ^= (pieces[start + i] < pieces[start + j]);
119 }
120 }
121 return (p);
122 }
123
124 // Convert number to permutation
125 protected void num2perm(int pieces[], int start, int len, int pos) {
126 // convert number pos into permutation of 0..len-1 and put it
127 // in array pieces[start..start+len-1]
128 int i, r;
129 int w[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
130 for (i = 0; i < len; i++) {
131 r = pos % (len - i);
132 pos = (pos - r) / (len - i);

Pagina 191 van 329 CubeThesis™ Depamelaere-Deschuytter


class Solver

133 pieces[start + i] = w[r]; // use r'th remaining piece


134 while (++r < len)
135 w[r - 1] = w[r]; // remove piece from list
136 }
137 }
138
139 // Convert number to partial permutation
140 protected void num2partperm(int pieces[], int start, int len, int np, int p0, int pos) {
141 // convert number pos into permutation of np pieces numbered p0..p0+np-1
142 // amongst len places 0..len-1 and put it
143 // in array pieces[start..start+len-1]
144 int i, j, r;
145 for (i = 0; i < np; i++) {
146 r = pos % (len - i);
147 pos = (pos - r) / (len - i);
148 for (j = start; j < start + len
149 && ((pieces[j] >= p0 && pieces[j] < p0 + np) || r > 0); j++) {
150 if (pieces[j] < p0 || pieces[j] >= p0 + np)
151 r--;
152 }
153 pieces[j] = p0 + i;
154 }
155 }
156
157 // Convert number to permutation
158 protected void num2ori(int pieces[], int start, int len, int val, int pos) {
159 // convert number pos into orientation of 0..val-1 and put it
160 // in array pieces[start..start+len-1]
161 int i, j = 0, k;
162 for (i = 0; i < len - 1; i++) {
163 k = pos % val;
164 j += val - k;
165 pos = (pos - k) / val;
166 pieces[start + i] = k;
167 }
168 pieces[start + len - 1] = j % val;
169 }
170
171 // Convert orientation to number
172 protected int ori2num(int pieces[], int start, int len, int val) {
173 int i, j = 0;
174 for (i = len - 2; i >= 0; i--)
175 j = j * val + (pieces[start + i] % val);
176 return (j);
177 }
178
179 // Convert full permutation to number
180 protected int perm2num(int[] pieces, int start, int len) {
181 // convert permutation of 0..len-1 in array pieces[start..start+len-1]
182 // into number
183 int i, j, r;
184 int p = 0;
185 for (i = len - 1; i >= 0; i--) {
186 r = 0;
187 for (j = i + 1; j < len; j++) {
188 if (pieces[start + j] < pieces[start + i]) {
189 r++;
190 }
191 }
192 p = p * (len - i) + r;
193 }
194 return p;
195 }
196
197 protected int partperm2num(int perm[], int len, int start, int p0, int np) {
198 int i, j, r, pos = 0;

Pagina 192 van 329 CubeThesis™ Depamelaere-Deschuytter


class Solver

199 for (i = np - 1; i >= 0; i--) {


200 r = 0;
201 for (j = 0; j < len && perm[start + j] != p0 + i; j++) {
202 if (perm[start + j] < p0 || perm[start + j] > p0 + i)
203 r++;
204 }
205 pos = pos * (len - i) + r;
206 }
207 return (pos);
208 }
209 }

Pagina 193 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

1 package solver.solverJS.algorithm;
2
3 // ----- Solver for the Anti-Slice group ----
4 import java.awt.event.*;
5
6 public final class SolverAntiSlice extends Solver {
7 int maxdepth; // current search depth
8 byte prune[][][][][];
9 byte pruneFace[];
10 int transFace[][];
11 final int transCorn[][] = { { 4, 0, 6, 2, 5, 1, 7, 3 }, // La
12 { 1, 2, 3, 0, 7, 4, 5, 6 }, // Ua
13 { 3, 5, 1, 7, 0, 6, 2, 4 } };// Fa
14
15 final int transEdge[][] = { { 4, 1, 6, 3, 8, 0, 10, 2, 5, 9, 7, 11 }, // La
16 { 1, 2, 3, 0, 4, 5, 6, 7, 11, 8, 9, 10 }, // Ua
17 { 0, 5, 2, 7, 3, 9, 1, 11, 8, 6, 10, 4 } };// Fa
18
19 final int transOri[][] = { { 2, 1, 0, 3 }, // La
20 { 0, 2, 1, 3 }, // Ua
21 { 0, 1, 3, 2 } };// Fa
22
23 public SolverAntiSlice(ActionListener m) {
24 super(m);
25 }
26
27 public MoveSequence getGenerator() {
28 int[] m = new int[sollen];
29 for (int i = 0; i < sollen; i++) {
30 m[i] = 15 + solmoves[i];
31 if (m[i] > 17)
32 m[i] -= 3;
33 }
34 return (new MoveSequence(sollen, m, solamount));
35 }
36
37 public void mix(CubePosition cubePos) {
38 int j;
39 // direct method, not random moves
40 cubePos.reset();
41
42 // edge orientation. 4 possibilities. face centres unaffected
43 j = (int) (4 * Math.random());
44 if (j == 1 || j == 3) {
45 cubePos.cubeletOri[12] = cubePos.cubeletOri[13] = cubePos.cubeletOri[14] =
46 cubePos.cubeletOri[15] = 1;
47 }
48 if (j > 1) {
49 cubePos.cubeletOri[8] = cubePos.cubeletOri[10] = cubePos.cubeletOri[16] =
50 cubePos.cubeletOri[18] = 1;
51 }
52 if (j == 1 || j == 2) {
53 cubePos.cubeletOri[9] = cubePos.cubeletOri[11] = cubePos.cubeletOri[17] =
54 cubePos.cubeletOri[19] = 1;
55 }
56
57 // set edges. first LR slice. 4 possibilities
58 j = (int) (4 * Math.random());
59 if (j < 2) {
60 swap(cubePos.cubeletPerm, 9, 11);
61 swap(cubePos.cubeletPerm, 17, 19);
62 swap(cubePos.cubeletPerm, 8, 10);
63 swap(cubePos.cubeletPerm, 16, 18);
64 // face centres unaffected
65 }
66 if (j == 1 || j == 3) {

Pagina 194 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

67 swap(cubePos.cubeletPerm, 9, 17);
68 swap(cubePos.cubeletPerm, 11, 19);
69 swap(cubePos.cubeletPerm, 13, 14);
70 swap(cubePos.cubeletPerm, 12, 15);
71 // face centres unaffected
72 }
73
74 // now FB slice. 4 possibilities
75 j = (int) (4 * Math.random());
76 if (j < 2) {
77 swap(cubePos.cubeletPerm, 8, 10);
78 swap(cubePos.cubeletPerm, 16, 18);
79 swap(cubePos.cubeletPerm, 12, 14);
80 swap(cubePos.cubeletPerm, 13, 15);
81 // face centres unaffected by 2x2H pattern
82 }
83 if (j == 1 || j == 3) {
84 swap(cubePos.cubeletPerm, 8, 18);
85 swap(cubePos.cubeletPerm, 10, 16);
86 swap(cubePos.cubeletPerm, 13, 14);
87 swap(cubePos.cubeletPerm, 12, 15);
88 // face centres unaffected
89 }
90
91 // random position of corners. 4*3*4*2 positions
92 // Maybe swap U/D corners
93 j = (int) (2 * Math.random());
94 if (j == 1) {
95 cubePos.doMove(0);
96 cubePos.doMove(3);
97 cubePos.doMove(0);
98 cubePos.doMove(3);
99 }
100 // rotate around UD axis
101 j = (int) (4 * Math.random());
102 while (j > 0) {
103 cubePos.doMove(1);
104 cubePos.doMove(4);
105 j--;
106 }
107 // rotate corner 1 in place
108 j = (int) (3 * Math.random());
109 while (j > 0) {
110 cubePos.doMove(0);
111 cubePos.doMove(3);
112 cubePos.doMove(1);
113 cubePos.doMove(4);
114 j--;
115 }
116
117 // tetrad 1,3,4,6 has been set
118 // set remaining tetrad
119 j = (int) (4 * Math.random());
120 if (j == 0) {
121 cubePos.doMove(0);
122 cubePos.doMove(3);
123 cubePos.doMove(1);
124 cubePos.doMove(4);
125 cubePos.doMove(0);
126 cubePos.doMove(3);
127 cubePos.doMove(0);
128 cubePos.doMove(3);
129 cubePos.doMove(0);
130 cubePos.doMove(3);
131 cubePos.doMove(2);
132 cubePos.doMove(5);

Pagina 195 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

133 cubePos.doMove(2);
134 cubePos.doMove(5);
135 cubePos.doMove(2);
136 cubePos.doMove(5);
137 } else if (j == 1) {
138 cubePos.doMove(1);
139 cubePos.doMove(4);
140 cubePos.doMove(2);
141 cubePos.doMove(5);
142 cubePos.doMove(1);
143 cubePos.doMove(4);
144 cubePos.doMove(1);
145 cubePos.doMove(4);
146 cubePos.doMove(1);
147 cubePos.doMove(4);
148 cubePos.doMove(0);
149 cubePos.doMove(3);
150 cubePos.doMove(0);
151 cubePos.doMove(3);
152 cubePos.doMove(0);
153 cubePos.doMove(3);
154 } else if (j == 2) {
155 cubePos.doMove(2);
156 cubePos.doMove(5);
157 cubePos.doMove(0);
158 cubePos.doMove(3);
159 cubePos.doMove(2);
160 cubePos.doMove(5);
161 cubePos.doMove(2);
162 cubePos.doMove(5);
163 cubePos.doMove(2);
164 cubePos.doMove(5);
165 cubePos.doMove(1);
166 cubePos.doMove(4);
167 cubePos.doMove(1);
168 cubePos.doMove(4);
169 cubePos.doMove(1);
170 cubePos.doMove(4);
171 }
172 }
173
174 public boolean setPosition(CubePosition cubePos, boolean test) {
175 int i, j;
176
177 // check corner orientation
178 // corners must have alternating orientation
179 for (i = 0; i < 7; i++) {
180 if (i == 3) {
181 j = cubePos.cubeletOri[0] + cubePos.cubeletOri[4];
182 } else {
183 j = cubePos.cubeletOri[i] + cubePos.cubeletOri[i + 1];
184 }
185 if (j != 0 && j != 3)
186 return (false);
187 }
188
189 // check edge orientation
190 // each slice must have same orientations
191 if (cubePos.cubeletOri[8] != cubePos.cubeletOri[10]
192 || cubePos.cubeletOri[8] != cubePos.cubeletOri[16]
193 || cubePos.cubeletOri[8] != cubePos.cubeletOri[18])
194 return (false);
195 if (cubePos.cubeletOri[9] != cubePos.cubeletOri[11]
196 || cubePos.cubeletOri[9] != cubePos.cubeletOri[17]
197 || cubePos.cubeletOri[9] != cubePos.cubeletOri[19])
198 return (false);

Pagina 196 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

199 if (cubePos.cubeletOri[12] != cubePos.cubeletOri[13]


200 || cubePos.cubeletOri[12] != cubePos.cubeletOri[14]
201 || cubePos.cubeletOri[12] != cubePos.cubeletOri[15])
202 return (false);
203 // an even number of edge slices is flipped
204 if ((cubePos.cubeletOri[8] ^ cubePos.cubeletOri[9] ^ cubePos.cubeletOri[12]) != 0)
205 return (false);
206
207 // check opposite faces same
208 if (cubieSettings.superGroup && (cubePos.cubeletOri[20] != cubePos.cubeletOri[23]
209 || cubePos.cubeletOri[21] != cubePos.cubeletOri[24]
210 || cubePos.cubeletOri[22] != cubePos.cubeletOri[25]))
211 return false;
212
213 // first copy array, so we can do a simple solve on it
214 int perm[] = new int[23];
215 for (i = 0; i < 20; i++)
216 perm[i] = cubePos.cubeletPerm[i];
217 for (i = 20; i < 23; i++)
218 perm[i] = cubePos.cubeletOri[i] & 1;
219
220 // solve corners
221 // align UD axis
222 if (cubePos.cubeletOri[0] == 1) { // do Fa'
223 perm[22] ^= 1;
224 cycle(perm, 0, 3, 7, 4);
225 cycle(perm, 1, 5, 6, 2);
226 cycle(perm, 9, 13, 17, 14);
227 cycle(perm, 11, 15, 19, 12);
228 } else if (cubePos.cubeletOri[0] == 2) { // do Ra'
229 perm[20] ^= 1;
230 cycle(perm, 0, 1, 5, 4);
231 cycle(perm, 3, 7, 6, 2);
232 cycle(perm, 8, 13, 16, 12);
233 cycle(perm, 10, 15, 18, 14);
234 }
235 // flip UD axis if necessary to bring 0 up
236 if (perm[4] == 0 || perm[5] == 0 || perm[6] == 0 || perm[7] == 0) {
237 // do Fa2
238 swap(perm, 0, 7);
239 swap(perm, 4, 3);
240 swap(perm, 1, 6);
241 swap(perm, 5, 2);
242 swap(perm, 11, 19);
243 swap(perm, 12, 15);
244 swap(perm, 9, 17);
245 swap(perm, 13, 14);
246 }
247
248 // turn 0 into position
249 while (perm[0] != 0) { // do Ua'
250 perm[21] ^= 1;
251 cycle(perm, 0, 1, 2, 3);
252 cycle(perm, 4, 7, 6, 5);
253 cycle(perm, 8, 9, 10, 11);
254 cycle(perm, 16, 19, 18, 17);
255 }
256
257 // Corner tetrad 0,2,5,7 should be solved now.
258 if (perm[0] != 0 || perm[2] != 2 || perm[5] != 5 || perm[7] != 7)
259 return (false);
260
261 // solve other tetrad using 4S patterns
262 if (perm[3] == 1) {
263 perm[20] ^= 1;
264 perm[22] ^= 1;

Pagina 197 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

265 swap(perm, 1, 3);


266 swap(perm, 4, 6);
267 swap(perm, 12, 14);
268 swap(perm, 13, 15);
269 } else if (perm[4] == 1) {
270 perm[21] ^= 1;
271 perm[22] ^= 1;
272 swap(perm, 1, 4);
273 swap(perm, 3, 6);
274 swap(perm, 9, 19);
275 swap(perm, 11, 17);
276 } else if (perm[6] == 1) {
277 perm[20] ^= 1;
278 perm[21] ^= 1;
279 swap(perm, 1, 6);
280 swap(perm, 3, 4);
281 swap(perm, 8, 18);
282 swap(perm, 10, 16);
283 }
284
285 // corner tetrad 1,3,4,6 should be solved now.
286 if (perm[1] != 1 || perm[3] != 3 || perm[4] != 4 || perm[6] != 6)
287 return (false);
288
289 // solve LR slice
290 if (perm[11] == 9) { // 4 vertical H on sides, no effect on face centre
291 swap(perm, 9, 11);
292 swap(perm, 17, 19);
293 swap(perm, 8, 10);
294 swap(perm, 16, 18);
295 } else if (perm[17] == 9) { // 4H on udlr, no effect on face centres
296 swap(perm, 9, 17);
297 swap(perm, 11, 19);
298 swap(perm, 13, 14);
299 swap(perm, 12, 15);
300 } else if (perm[19] == 9) { // 2H (ud) 2X (fb), no effect on face centres
301 swap(perm, 9, 19);
302 swap(perm, 11, 17);
303 swap(perm, 12, 13);
304 swap(perm, 14, 15);
305 }
306 if (perm[9] != 9 || perm[11] != 11 || perm[17] != 17 || perm[19] != 19)
307 return (false);
308
309 // solve FB slice
310 if (perm[10] == 8) {
311 // 2H (fb) 2X (lr) sides, no effect on face centres
312 swap(perm, 8, 10);
313 swap(perm, 16, 18);
314 swap(perm, 12, 14);
315 swap(perm, 13, 15);
316 } else if (perm[18] == 8) {
317 // 2H (ud) 2X (lr), no effect on face centres
318 swap(perm, 8, 18);
319 swap(perm, 10, 16);
320 swap(perm, 13, 14);
321 swap(perm, 12, 15);
322 } else if (perm[16] == 8) {
323 // 4H (udfb), no effect on face centres
324 swap(perm, 8, 16);
325 swap(perm, 10, 18);
326 swap(perm, 12, 13);
327 swap(perm, 14, 15);
328 }
329
330 for (i = 0; i < 20; i++)

Pagina 198 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

331 if (perm[i] != i)
332 return (false);
333 if (cubieSettings.superGroup) {
334 for (i = 20; i < 23; i++)
335 if (perm[i] != 0)
336 return (false);
337 }
338
339 if (test)
340 return (true);
341 if (!prepared)
342 return (false);
343
344 // convert to numbers
345 for (i = 0; i < 8; i++) {
346 if (cubePos.cubeletPerm[i] == 0)
347 perm[0] = i;
348 }
349 for (i = 8; i < 20; i++) {
350 if (cubePos.cubeletPerm[i] == 8)
351 perm[1] = i - 8;
352 else if (cubePos.cubeletPerm[i] == 9)
353 perm[2] = i - 8;
354 else if (cubePos.cubeletPerm[i] == 12)
355 perm[3] = i - 8;
356 }
357 perm[4] = cubePos.cubeletOri[8] * 2 + cubePos.cubeletOri[9];
358 if (cubieSettings.superGroup) {
359 perm[5] = (cubePos.cubeletOri[20] << 4)
360 + (cubePos.cubeletOri[21] << 2)
361 + cubePos.cubeletOri[22];
362 } else {
363 perm[5] = -1;
364 }
365
366 if (positionlist == null) {
367 positionlist = new int[40][6];
368 maxdepth = sollen = 0;
369 solmoves[0] = -1;
370 solamount[0] = 3;
371 } else if (positionlist[0][0] != perm[0] || positionlist[0][1] != perm[1]
372 || positionlist[0][2] != perm[2] || positionlist[0][3] != perm[3]
373 || positionlist[0][4] != perm[4] || positionlist[0][5] != perm[5]) {
374 // clear out search history
375 maxdepth = sollen = 0;
376 solmoves[0] = -1;
377 solamount[0] = 3;
378 }
379 // set position
380 positionlist[0][0] = perm[0];
381 positionlist[0][1] = perm[1];
382 positionlist[0][2] = perm[2];
383 positionlist[0][3] = perm[3];
384 positionlist[0][4] = perm[4];
385 positionlist[0][5] = perm[5];
386 return (true);
387 }
388
389 // initialise tables
390 protected void init() {
391 int i1, i2, i3, i4, i5, k, m, q, j1, j2, j3, j4, j5;
392 transFace = new int[3][64];
393 prune = new byte[8][12][12][12][4];
394 pruneFace = new byte[64];
395
396 // calculate transition/pruning table for face centres

Pagina 199 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

397 k = 0;
398 for (i1 = 0; i1 < 4; i1++)
399 for (i2 = 0; i2 < 4; i2++)
400 for (i3 = 0; i3 < 4; i3++) {
401 transFace[0][k] = (((i1 + 3) & 3) << 4) + (i2 << 2) + i3;
402 transFace[1][k] = (i1 << 4) + (((i2 + 3) & 3) << 2) + i3;
403 transFace[2][k] = (i1 << 4) + (i2 << 2) + ((i3 + 3) & 3);
404 pruneFace[k] = 1;
405 if (i1 != 0)
406 pruneFace[k]++;
407 if (i2 != 0)
408 pruneFace[k]++;
409 if (i3 != 0)
410 pruneFace[k]++;
411 k++;
412 }
413
414 // calculate pruning tables
415 int l = 1;
416 prune[0][0][1][4][0] = 1;
417 do {
418 k = 0;
419 for (i1 = 0; i1 < 8; i1++)
420 for (i2 = 0; i2 < 12; i2++)
421 for (i3 = 0; i3 < 12; i3++)
422 for (i4 = 0; i4 < 12; i4++)
423 for (i5 = 0; i5 < 4; i5++) {
424 if (prune[i1][i2][i3][i4][i5] == l) {
425 for (m = 0; m < 3; m++) {
426 j1 = i1;
427 j2 = i2;
428 j3 = i3;
429 j4 = i4;
430 j5 = i5;
431 for (q = 0; q < 3; q++) {
432 j1 = transCorn[m][j1];
433 j2 = transEdge[m][j2];
434 j3 = transEdge[m][j3];
435 j4 = transEdge[m][j4];
436 j5 = transOri[m][j5];
437 if (prune[j1][j2][j3][j4][j5] == 0) {
438 prune[j1][j2][j3][j4][j5] = (byte) (l + 1);
439 k++;
440 }
441 }
442 }
443 }
444 }
445 l++;
446 } while (k != 0);
447 }
448
449 // solve a position
450 protected boolean solve() {
451 // do IDA* - search depth first for each maxdepth.
452 while (!search()) {
453 if (wanttostop)
454 return (false);
455 maxdepth++;
456 }
457 return (true);
458 }
459
460 private boolean search() {
461 // do a depth search through all positions at depth maxdepth.
462 // return false if no solution, or break out with true if solved.

Pagina 200 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

463 int m, nxt;


464 // do check for solved position with null solution.
465 if (maxdepth == 0 && sollen == 0 && positionlist[0][0] == 0 && positionlist[0][1] == 0
466 && positionlist[0][2] == 1 && positionlist[0][3] == 4 && positionlist[0][4] == 0
467 && positionlist[0][5] <= 0) {
468 return (true);
469 }
470
471 while (sollen >= 0) {
472 // at this point positionlist[0..sollen] are visited positions
473 // and solmoves[0..sollen-1] are moves performed.
474 // Note solmoves[sollen] is last tried (rejected) next move
475 nxt = sollen + 1;
476 // add extra quarter turn to last move
477 m = solmoves[sollen];
478 if (m >= 0) { // ignore dummy -1 move
479 positionlist[nxt][0] = transCorn[m][positionlist[nxt][0]];
480 positionlist[nxt][1] = transEdge[m][positionlist[nxt][1]];
481 positionlist[nxt][2] = transEdge[m][positionlist[nxt][2]];
482 positionlist[nxt][3] = transEdge[m][positionlist[nxt][3]];
483 positionlist[nxt][4] = transOri[m][positionlist[nxt][4]];
484 if (cubieSettings.superGroup)
485 positionlist[nxt][5] = transFace[m][positionlist[nxt][5]];
486 } else {
487 positionlist[nxt][0] = positionlist[sollen][0];
488 positionlist[nxt][1] = positionlist[sollen][1];
489 positionlist[nxt][2] = positionlist[sollen][2];
490 positionlist[nxt][3] = positionlist[sollen][3];
491 positionlist[nxt][4] = positionlist[sollen][4];
492 positionlist[nxt][5] = positionlist[sollen][5];
493 }
494 solamount[sollen]++;
495 // if done full turn, then move to next face
496 if (solamount[sollen] > 3) {
497 // next face, 0 turns yet
498 solamount[sollen] = 0;
499 do {
500 solmoves[sollen]++;
501 } while (sollen != 0 && solmoves[sollen] == solmoves[sollen - 1]);
502 if (solmoves[sollen] >= 3) {
503 // done all faces. backtrack
504 sollen--;
505 continue;
506 }
507 continue; // loop back to do a quarter turn of this new face
508 }
509
510 // check pruning for proposed new position
511 if (sollen
512 +prune[positionlist[nxt][0]]
513 [positionlist[nxt][1]]
514 [positionlist[nxt][2]]
515 [positionlist[nxt][3]]
516 [positionlist[nxt][4]] < maxdepth + 1
517 && (!cubieSettings.superGroup
518 || sollen + pruneFace[positionlist[nxt][5]] < maxdepth + 1)) {
519 // its ok, officially add to movelist
520 // append dummy move to list for later extension.
521 solmoves[nxt] = -1;
522 solamount[nxt] = 3;
523 sollen = nxt;
524 // check if have found solution of required length;
525 if (sollen >= maxdepth)
526 return (true);
527 }
528

Pagina 201 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverAntiSlice

529 if (wanttostop)
530 return (false);
531 // loop back to shift to next move sequence
532 }
533 // reset for next search
534 solmoves[0] = -1;
535 solamount[0] = 3;
536 sollen = 0;
537 return (false);
538 }
539 }

Pagina 202 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

1 package solver.solverJS.algorithm;
2
3 // ----- Solver for the full group, kociemba 2-phase ----
4 import java.awt.event.*;
5
6 public final class SolverKociemba extends Solver {
7 // position = cornerperm 40320, cornerori 2187, edgeori 2048,
8 // midslicefull 11880=12!/8! for all three slices
9 // in phase 2 two slices become one set 40320.
10 // centresori 4096 (redundancy factor of 2)
11 // Pruning:
12 // phase 1. orientations 2^11=2048, 3^7=2187, slicechoice:12C4=495
13 // phase 2. corners 8!=40320, edgesUD 8!=40320, edgesM 4!=24
14 int transEdgeOri[][];
15 int transCornOri[][];
16 int transCornPerm[][];
17 int transSliceFull[][];
18 int transEdgePerm[][];
19 int transSlicePerm[][];
20 int transChoice[][];
21 int transFace[][];
22
23 byte pruneEdgeOri[];
24 byte pruneCornOri[];
25 byte pruneChoice[];
26 byte pruneCornPerm[];
27 byte pruneEdgePerm[];
28 byte pruneSlicePerm[];
29 byte pruneFace1[];
30 byte pruneFace2[];
31 int phase1len = 0; // current search depth for phase1
32 int phase2len = 0; // current search depth for phase2
33 int maxdepth = 25; // length of best solution found (phase1+phase2)
34
35 public SolverKociemba(ActionListener m) {
36 super(m);
37 }
38
39 public MoveSequence getGenerator() {
40 // sollen = solutionLength ...
41 return (new MoveSequence(sollen, solmoves, solamount));
42 }
43
44 public void mix(CubePosition cubePos) {
45 int i;
46 // direct method, not random moves
47 cubePos.reset();
48 do {
49 num2perm(cubePos.cubeletPerm, 0, 8, (int) (40320 * Math.random()));
50 num2perm(cubePos.cubeletPerm, 8, 12, (int) (479001600 * Math.random()));
51 for (i = 8; i < 20; i++)
52 cubePos.cubeletPerm[i] += 8;
53 } while (parityOdd(cubePos.cubeletPerm, 0, 20));
54
55 num2ori(cubePos.cubeletOri, 0, 8, 3, (int) (2187 * Math.random()));
56 num2ori(cubePos.cubeletOri, 8, 12, 2, (int) (2048 * Math.random()));
57 num2ori(cubePos.cubeletOri, 20, 6, 4, (int) (1024 * Math.random()));
58 if (Math.random() < .5)
59 cubePos.cubeletOri[25] ^= 2;
60 if (parityOdd(cubePos.cubeletPerm, 0, 8))
61 cubePos.cubeletOri[25] ^= 1;
62 }
63
64 public boolean setPosition(CubePosition cubePos, boolean test) {
65 int i, j = 0;
66 for (i = 0; i < 8; i++) {

Pagina 203 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

67 j += cubePos.cubeletOri[i];
68 if (j > 2)
69 j -= 3;
70 }
71 if (j != 0)
72 return (false);
73 j = 0;
74 for (i = 8; i < 20; i++) {
75 j += cubePos.cubeletOri[i];
76 if (j > 1)
77 j -= 2;
78 }
79 if (j != 0)
80 return (false);
81 if (cubieSettings.superGroup) {
82 boolean f = parityOdd(cubePos.cubeletPerm, 0, 8);
83 for (i = 20; i < 26; i++) {
84 if ((cubePos.cubeletOri[i] & 1) != 0)
85 f = !f;
86 }
87 if (f)
88 return (false);
89 }
90 if (parityOdd(cubePos.cubeletPerm, 0, 20))
91 return (false);
92
93 if (test)
94 return (true);
95 if (!prepared)
96 return (false);
97
98 // convert position to numbers
99 int newpos[] = new int[8];
100 newpos[0] = 0;
101 for (i = 10; i >= 0; i--)
102 newpos[0] = newpos[0] * 2 + cubePos.cubeletOri[8 + i];
103 newpos[1] = 0;
104 for (i = 6; i >= 0; i--)
105 newpos[1] = newpos[1] * 3 + cubePos.cubeletOri[i];
106 newpos[2] = perm2num(cubePos.cubeletPerm, 0, 8);
107 newpos[3] = partperm2num(cubePos.cubeletPerm, 12, 8, 8, 4);
108 newpos[4] = partperm2num(cubePos.cubeletPerm, 12, 8, 12, 4);
109 newpos[5] = partperm2num(cubePos.cubeletPerm, 12, 8, 16, 4);
110 newpos[6] = 0;
111 for (i = 10; i >= 0; i--)
112 newpos[6] = newpos[6] * 2
113 +((cubePos.cubeletPerm[8 + i] >= 12
114 && cubePos.cubeletPerm[8 + i] < 16) ? 1
115 : 0);
116 if (cubieSettings.superGroup) {
117 newpos[7] = 0;
118 for (i = 20; i < 26; i++)
119 newpos[7] = newpos[7] * 4 + cubePos.cubeletOri[i];
120 } else {
121 newpos[7] = -1;
122 }
123
124 // clear search history if are using a different position
125 if (positionlist == null) {
126 positionlist = new int[40][10];
127 sollen = phase1len = phase2len = 0;
128 maxdepth = 25;
129 solmoves[0] = -1;
130 solamount[0] = 3;
131 } else if (positionlist[0][0] != newpos[0]
132 || positionlist[0][1] != newpos[1]

Pagina 204 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

133 || positionlist[0][2] != newpos[2]


134 || positionlist[0][3] != newpos[3]
135 || positionlist[0][4] != newpos[4]
136 || positionlist[0][5] != newpos[5]
137 || positionlist[0][6] != newpos[6]
138 || positionlist[0][9] != newpos[7]) {
139 sollen = phase1len = phase2len = 0;
140 maxdepth = 25;
141 solmoves[0] = -1;
142 solamount[0] = 3;
143 }
144 positionlist[0][0] = newpos[0]; // edge ori
145 positionlist[0][1] = newpos[1]; // corn ori
146 positionlist[0][2] = newpos[2]; // corn perm
147 positionlist[0][3] = newpos[3]; // edge perm1
148 positionlist[0][4] = newpos[4]; // edge perm2
149 positionlist[0][5] = newpos[5]; // edge perm3
150 positionlist[0][6] = newpos[6]; // choice
151 positionlist[0][9] = newpos[7]; // face centres
152 return (true);
153 }
154
155 protected boolean solve() {
156 // do IDA* - search depth first for each phase1len.
157
158 // quit if no better solution possible
159 if (phase1len >= maxdepth)
160 return (false);
161
162 // System.out.println("p1 len="+phase1len);
163 while (!search1()) {
164 if (wanttostop)
165 return (false);
166 phase1len++;
167 if (phase1len >= maxdepth)
168 return (false);
169 // System.out.println("p1 len="+phase1len);
170 }
171 // found a solution
172 maxdepth = sollen - 1;
173 return (true);
174 }
175
176 private boolean search1() {
177 // do a depth search through all phase1 positions at depth phase1len.
178 // return false if no solution, or break out with true if solved.
179 int m, nxt;
180
181 // Check if had already completed phase 1 section
182 if (sollen >= phase1len) {
183 // if have phase1 solution at end of phase1, then try alternative phase2
184 // solution first
185 if (positionlist[phase1len][0] == 0
186 && positionlist[phase1len][1] == 0
187 && positionlist[phase1len][6] == 240
188 && (!cubieSettings.superGroup
189 || (positionlist[phase1len][9] & 0x451) == 0)) {
190 // find next phase2 solution if possible
191 if (solve2())
192 return (true);
193 // no alternative phase 2 solution found. continue with phase1
194 }
195 sollen = phase1len;
196 }
197
198 while (sollen >= 0) {

Pagina 205 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

199 // at this point positionlist[0..sollen] are visited positions


200 // and solmoves[0..sollen-1] are moves performed.
201 // Note solmoves[sollen] is last tried (rejected) next move
202 nxt = sollen + 1;
203 // add extra quarter turn to last move
204 m = solmoves[sollen];
205 if (m >= 0) { // ignore dummy -1 move
206 positionlist[nxt][0] = transEdgeOri[positionlist[nxt][0]][m];
207 positionlist[nxt][1] = transCornOri[positionlist[nxt][1]][m];
208 positionlist[nxt][2] = transCornPerm[positionlist[nxt][2]][m];
209 positionlist[nxt][3] = transSliceFull[positionlist[nxt][3]][m];
210 positionlist[nxt][4] = transSliceFull[positionlist[nxt][4]][m];
211 positionlist[nxt][5] = transSliceFull[positionlist[nxt][5]][m];
212 positionlist[nxt][6] = transChoice[positionlist[nxt][6]][m];
213 if (cubieSettings.superGroup)
214 positionlist[nxt][9] = transFace[positionlist[nxt][9]][m];
215 } else {
216 positionlist[nxt][0] = positionlist[sollen][0];
217 positionlist[nxt][1] = positionlist[sollen][1];
218 positionlist[nxt][2] = positionlist[sollen][2];
219 positionlist[nxt][3] = positionlist[sollen][3];
220 positionlist[nxt][4] = positionlist[sollen][4];
221 positionlist[nxt][5] = positionlist[sollen][5];
222 positionlist[nxt][6] = positionlist[sollen][6];
223 positionlist[nxt][9] = positionlist[sollen][9];
224 }
225 solamount[sollen]++;
226 // if done full turn, then move to next face
227 if (solamount[sollen] > 3) {
228 // next face, 0 turns yet
229 solamount[sollen] = 0;
230 do {
231 solmoves[sollen]++;
232 } while (sollen != 0 && (solmoves[sollen] == solmoves[sollen - 1]
233 || solmoves[sollen] == solmoves[sollen - 1] + 3));
234 if (solmoves[sollen] >= 6) {
235 // done all faces. backtrack
236 sollen--;
237 continue;
238 }
239 continue; // loop back to do a quarter turn of this new face
240 }
241
242 // check pruning for proposed new position
243 if (sollen + pruneEdgeOri[positionlist[nxt][0]] < phase1len + 1
244 && sollen + pruneCornOri[positionlist[nxt][1]] < phase1len + 1
245 && sollen + pruneChoice[positionlist[nxt][6]] < phase1len + 1
246 && (!cubieSettings.superGroup
247 || sollen + pruneFace1[positionlist[nxt][9]] < phase1len + 1)) {
248 // its ok, officially add to movelist
249 // append dummy move to list for later extension.
250 solmoves[nxt] = -1;
251 solamount[nxt] = 3;
252 sollen = nxt;
253 // check if have found phase1 solution of required length;
254 if (sollen >= phase1len) {
255 // find phase2 solution if possible
256 if (solve2())
257 return (true);
258 // no phase 2 solution found. continue with phase1
259 // sollen=phase1len;
260 }
261 }
262 if (wanttostop)
263 return (false);
264 // loop back to shift to next move sequence

Pagina 206 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

265 }
266 // reset for next search
267 solmoves[0] = -1;
268 solamount[0] = 3;
269 sollen = 0;
270 return (false);
271 }
272
273 private boolean solve2() {
274 // should not search further if last phase1 move
275 // could have been done in phase 2
276 if (sollen > 0) {
277 if (solamount[sollen - 1] == 2 || solmoves[sollen - 1] == 1
278 || solmoves[sollen - 1] == 4)
279 return (false);
280 }
281 // quick prune on corners before doing position conversion
282 if(phase1len + pruneCornPerm[positionlist[phase1len][2]] > maxdepth + 1
283 || (cubieSettings.superGroup
284 && phase1len + pruneFace2[positionlist[phase1len][9]] >
285 maxdepth + 1)) {
286 return (false);
287 }
288
289 // get depth to start phase 2 search with
290 phase2len = sollen - phase1len;
291 if (sollen > maxdepth) {
292 phase2len = maxdepth - phase1len;
293 }
294
295 // if just finished phase1, then convert phase1 end position
296 // to phase2 start position
297 if (phase2len == 0) {
298 // check if already finished
299 if(positionlist[phase1len][2] == 0 && positionlist[phase1len][3] == 0
300 && positionlist[phase1len][4] == 5860
301 && positionlist[phase1len][5] == 11720
302 && positionlist[phase1len][9] <= 0)
303 return (true);
304
305 // convert edge pos numbers into full edge permutation
306 int edges[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
307 num2partperm(edges, 0, 12, 4, 0, positionlist[phase1len][3]);
308 num2partperm(edges, 0, 12, 4, 4, positionlist[phase1len][4]);
309 num2partperm(edges, 0, 12, 4, 8, positionlist[phase1len][5]);
310
311 // check that face centres can be solved given this middle slice
312 if (cubieSettings.superGroup) {
313 boolean par = parityOdd(edges, 4, 4);
314 if ((positionlist[phase1len][9] & 2) != 0)
315 par = !par;
316 if ((positionlist[phase1len][9] & 32) != 0)
317 par = !par;
318 if ((positionlist[phase1len][9] & 128) != 0)
319 par = !par;
320 if ((positionlist[phase1len][9] & 2048) != 0)
321 par = !par;
322 if (par)
323 return (false);
324 }
325
326 // convert middle slice to number
327 positionlist[phase1len][8] = perm2num(edges, 4, 4);
328 edges[4] = edges[8];
329 edges[5] = edges[9];
330 edges[6] = edges[10];

Pagina 207 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

331 edges[7] = edges[11];


332 // convert UD edges to number
333 positionlist[phase1len][7] = perm2num(edges, 0, 8);
334
335 }
336
337 // do IDA* - search depth first for each phase2len.
338 // System.out.println("p2 len="+phase2len);
339 while (!search2()) {
340 phase2len++;
341 if (phase1len + phase2len > maxdepth)
342 return (false);
343 // System.out.println("p2 len="+phase2len);
344 }
345 return (true);
346 }
347
348 private boolean search2() {
349 // do a phase2 depth search through all positions at depth phase2len.
350 // return false if no solution, or break out with true if solved.
351 int m, nxt;
352 while (sollen >= phase1len) {
353 // at this point positionlist[0..sollen] are visited positions
354 // and solmoves[0..sollen-1] are moves performed.
355 // Note solmoves[sollen] is last tried (rejected) next move
356 nxt = sollen + 1;
357 // add extra turn to last move
358 m = solmoves[sollen];
359 if (m == 1 || m == 4) { // U or D move
360 positionlist[nxt][2] = transCornPerm[positionlist[nxt][2]][m];
361 positionlist[nxt][7] = transEdgePerm[positionlist[nxt][7]][m];
362 // positionlist[nxt][8]=transSlicePerm[positionlist[nxt][8]][m]; //
363 // slice is unaffected anyway
364 if (cubieSettings.superGroup)
365 positionlist[nxt][9] = transFace[positionlist[nxt][9]][m];
366 } else if (m >= 0) {
367 positionlist[nxt][2] = transCornPerm[transCornPerm[positionlist
368 [nxt][2]][m]][m];
369 positionlist[nxt][7] = transEdgePerm[positionlist[nxt][7]][m];
370 positionlist[nxt][8] = transSlicePerm[positionlist[nxt][8]][m];
371 if (cubieSettings.superGroup)
372 positionlist[nxt][9] = transFace[transFace[positionlist
373 [nxt][9]][m]][m];
374 } else { // ignore dummy -1 move
375 positionlist[nxt][2] = positionlist[sollen][2];
376 positionlist[nxt][7] = positionlist[sollen][7];
377 positionlist[nxt][8] = positionlist[sollen][8];
378 positionlist[nxt][9] = positionlist[sollen][9];
379 }
380 solamount[sollen] += (m == 1 || m == 4) ? 1 : 2;
381 // if done full turn, then move to next face
382 if (solamount[sollen] > 3) {
383 // next face, 0 turns yet
384 solamount[sollen] = 0;
385 do {
386 solmoves[sollen]++;
387 } while (sollen != 0 && (solmoves[sollen] == solmoves[sollen - 1]
388 || solmoves[sollen] == solmoves[sollen - 1] + 3));
389 if (solmoves[sollen] >= 6) {
390 // done all faces. backtrack
391 sollen--;
392 continue;
393 }
394 continue; // loop back to do a turn of this new face
395 }
396

Pagina 208 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

397 // check pruning for proposed new position


398 if (sollen + pruneEdgePerm[positionlist[nxt][7]] <
399 phase1len + phase2len + 1
400 && sollen + pruneCornPerm[positionlist[nxt][2]] <
401 phase1len + phase2len + 1
402 && sollen + pruneSlicePerm[positionlist[nxt][8]] <
403 phase1len + phase2len + 1
404 && (!cubieSettings.superGroup
405 || sollen + pruneFace2[positionlist[nxt][9]] <
406 phase1len + phase2len + 1)) {
407 // its ok, officially add to movelist
408 // append dummy move to list for later extension.
409 solmoves[nxt] = -1;
410 solamount[nxt] = 3;
411 sollen = nxt;
412 // check if have found phase2 solution of required length;
413 if (sollen >= phase1len + phase2len)
414 return (true);
415 }
416
417 if (wanttostop)
418 return (false);
419 // loop back to shift to next move sequence
420 }
421 // reset for next search
422 solmoves[phase1len] = -1;
423 solamount[phase1len] = 3;
424 sollen = phase1len;
425 return (false);
426 }
427
428 protected void init() {
429 // position = cornerperm 40320, cornerori 2187, edgeori 2048,
430 // midslicefull 11880=12!/8! for all three slices
431 // in phase 2 two slices become one set 40320.
432 // Pruning:
433 // phase 1. orientations 2^11=2048, 3^7=2187, slicechoice:12C4=495
434 // phase 2. corners 8!=40320, edgesUD 8!=40320, edgesM 4!=24
435 transEdgeOri = new int[2048][6];
436 transCornOri = new int[2187][6];
437 transCornPerm = new int[40320][6];
438 transEdgePerm = new int[40320][6];
439 transSliceFull = new int[11880][6];
440 transChoice = new int[2048][6];
441 transSlicePerm = new int[24][6];
442 transFace = new int[4096][6];
443 pruneEdgeOri = new byte[2048];
444 pruneCornOri = new byte[2187];
445 pruneChoice = new byte[2048];
446 pruneCornPerm = new byte[40320];
447 pruneEdgePerm = new byte[40320];
448 pruneSlicePerm = new byte[24];
449 pruneFace1 = new byte[4096];
450 pruneFace2 = new byte[4096];
451 int i, m;
452 // calc transition tables
453 for (i = 0; i < 2048; i++) { // edge orientation transitions
454 for (m = 0; m < 6; m++)
455 transEdgeOri[i][m] = gettransEdgeOri(i, m);
456 }
457 for (i = 0; i < 2187; i++) { // corner orientation transitions
458 for (m = 0; m < 6; m++)
459 transCornOri[i][m] = gettransCornOri(i, m);
460 }
461 for (i = 0; i < 40320; i++) { // corner permutation transitions
462 for (m = 0; m < 6; m++)

Pagina 209 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

463 transCornPerm[i][m] = gettransCornPerm(i, m);


464 }
465 for (i = 0; i < 40320; i++) { // edge permutation transitions
466 for (m = 0; m < 6; m++)
467 transEdgePerm[i][m] = gettransEdgePerm(i, m);
468 }
469 for (i = 0; i < 11880; i++) { // slice permutation transitions
470 for (m = 0; m < 6; m++)
471 transSliceFull[i][m] = gettransSliceFull(i, m);
472 }
473 for (i = 0; i < 2048; i++) { // slice choice transitions
474 for (m = 0; m < 6; m++)
475 transChoice[i][m] = gettransChoice(i, m);
476 }
477 for (i = 0; i < 24; i++) { // slice permutation transitions
478 for (m = 0; m < 6; m++)
479 transSlicePerm[i][m] = gettransSlicePerm(i, m);
480 }
481
482 for (i = 0; i < 4096; i++) { // face centre orientation transitions
483 transFace[i][0] = ((i + (3 << 10)) & ((1 << 12) - 1));
484 transFace[i][1] = ((i + (3 << 8)) & ((1 << 10) - 1))
485 + (i & ((1 << 12) - (1 << 10)));
486 transFace[i][2] = ((i + (3 << 6)) & ((1 << 8) - 1)) + (i & ((1 << 12) - (1 << 8)));
487 transFace[i][3] = ((i + (3 << 4)) & ((1 << 6) - 1)) + (i & ((1 << 12) - (1 << 6)));
488 transFace[i][4] = ((i + (3 << 2)) & ((1 << 4) - 1)) + (i & ((1 << 12) - (1 << 4)));
489 transFace[i][5] = ((i + (3)) & ((1 << 2) - 1)) + (i & ((1 << 12) - (1 << 2)));
490 }
491
492 // calculate pruning tables. First edge orientation
493 int p, q, k;
494 int l = 1;
495 pruneEdgeOri[0] = 1;
496 do {
497 k = 0;
498 for (i = 0; i < 2048; i++) {
499 if (pruneEdgeOri[i] == l) {
500 for (m = 0; m < 6; m++) {
501 p = i;
502 for (q = 0; q < 3; q++) {
503 p = transEdgeOri[p][m];
504 if (pruneEdgeOri[p] == 0) {
505 pruneEdgeOri[p] = (byte) (l + 1);
506 k++;
507 }
508 }
509 }
510 }
511 }
512 l++;
513 } while (k != 0);
514
515 // corner orientation pruning
516 l = 1;
517 pruneCornOri[0] = 1;
518 do {
519 k = 0;
520 for (i = 0; i < 2187; i++) {
521 if (pruneCornOri[i] == l) {
522 for (m = 0; m < 6; m++) {
523 p = i;
524 for (q = 0; q < 3; q++) {
525 p = transCornOri[p][m];
526 if (pruneCornOri[p] == 0) {
527 pruneCornOri[p] = (byte) (l + 1);
528 k++;

Pagina 210 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

529 }
530 }
531 }
532 }
533 }
534 l++;
535 } while (k != 0);
536
537 // slice choice pruning
538 l = 1;
539 pruneChoice[240] = 1;
540 do {
541 k = 0;
542 for (i = 0; i < 2048; i++) {
543 if (pruneChoice[i] == l) {
544 for (m = 0; m < 6; m++) {
545 p = i;
546 for (q = 0; q < 3; q++) {
547 p = transChoice[p][m];
548 if (pruneChoice[p] == 0) {
549 pruneChoice[p] = (byte) (l + 1);
550 k++;
551 }
552 }
553 }
554 }
555 }
556 l++;
557 } while (k != 0);
558
559 // corner perm pruning
560 l = 1;
561 pruneCornPerm[0] = 1;
562 do {
563 k = 0;
564 for (i = 0; i < 40320; i++) {
565 if (pruneCornPerm[i] == l) {
566 for (m = 0; m < 6; m++) {
567 p = i;
568 for (q = 0; q < 3; q++) {
569 p = transCornPerm[p][m];
570 if (m == 1 || m == 4 || q == 1) {
571 if (pruneCornPerm[p] == 0) {
572 pruneCornPerm[p] = (byte) (l + 1);
573 k++;
574 }
575 }
576 }
577 }
578 }
579 }
580 l++;
581 } while (k != 0);
582
583 // edge perm pruning
584 l = 1;
585 pruneEdgePerm[0] = 1;
586 do {
587 k = 0;
588 for (i = 0; i < 40320; i++) {
589 if (pruneEdgePerm[i] == l) {
590 for (m = 0; m < 6; m++) {
591 p = i;
592 for (q = 0; q < 3; q++) {
593 p = transEdgePerm[p][m];
594 if (pruneEdgePerm[p] == 0) {

Pagina 211 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

595 pruneEdgePerm[p] = (byte) (l + 1);


596 k++;
597 }
598 }
599 }
600 }
601 }
602 l++;
603 } while (k != 0);
604
605 // slice perm pruning
606 l = 1;
607 pruneSlicePerm[0] = 1;
608 do {
609 k = 0;
610 for (i = 0; i < 24; i++) {
611 if (pruneSlicePerm[i] == l) {
612 for (m = 0; m < 6; m++) {
613 p = i;
614 for (q = 0; q < 3; q++) {
615 p = transSlicePerm[p][m];
616 if (pruneSlicePerm[p] == 0) {
617 pruneSlicePerm[p] = (byte) (l + 1);
618 k++;
619 }
620 }
621 }
622 }
623 }
624 l++;
625 } while (k != 0);
626
627 // face centre orientation pruning table
628 for (i = 0; i < 4096; i++) {
629 pruneFace1[i] = 1;
630 if ((i & 1) != 0)
631 pruneFace1[i]++;
632 if ((i & 16) != 0)
633 pruneFace1[i]++;
634 if ((i & 64) != 0)
635 pruneFace1[i]++;
636 if ((i & 1024) != 0)
637 pruneFace1[i]++;
638 pruneFace2[i] = 1;
639 if ((i & 3) != 0)
640 pruneFace2[i]++;
641 if ((i & 12) != 0)
642 pruneFace2[i]++;
643 if ((i & 48) != 0)
644 pruneFace2[i]++;
645 if ((i & 192) != 0)
646 pruneFace2[i]++;
647 if ((i & 768) != 0)
648 pruneFace2[i]++;
649 if ((i & 3072) != 0)
650 pruneFace2[i]++;
651 }
652
653 prepared = true;
654 }
655
656 private int gettransEdgeOri(int pos, int m) {
657 // convert pos number into orientation
658 int edges[] = new int[12];
659 num2ori(edges, 0, 12, 2, pos);
660

Pagina 212 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

661 // do move L U F R D B
662 if (m == 3) {
663 cycle(edges, 0, 5, 8, 4);
664 edges[0] ^= 1;
665 edges[5] ^= 1;
666 edges[8] ^= 1;
667 edges[4] ^= 1;
668 } else if (m == 2) {
669 cycle(edges, 1, 6, 9, 5);
670 } else if (m == 0) {
671 cycle(edges, 2, 7, 10, 6);
672 edges[2] ^= 1;
673 edges[7] ^= 1;
674 edges[10] ^= 1;
675 edges[6] ^= 1;
676 } else if (m == 5) {
677 cycle(edges, 3, 4, 11, 7);
678 } else if (m == 1) {
679 cycle(edges, 3, 2, 1, 0);
680 } else if (m == 4) {
681 cycle(edges, 8, 9, 10, 11);
682 }
683 // convert back to number
684 return (ori2num(edges, 0, 12, 2));
685 }
686
687 private int gettransCornOri(int pos, int m) {
688 // convert pos number into permutation
689 int corners[] = new int[8];
690 num2ori(corners, 0, 8, 3, pos);
691
692 // do move L U F R D B
693 if (m == 3) {
694 cycle(corners, 0, 1, 5, 4);
695 corners[0] += 2;
696 corners[1]++;
697 corners[5] += 2;
698 corners[4]++;
699 } else if (m == 2) {
700 cycle(corners, 1, 2, 6, 5);
701 corners[1] += 2;
702 corners[2]++;
703 corners[6] += 2;
704 corners[5]++;
705 } else if (m == 0) {
706 cycle(corners, 2, 3, 7, 6);
707 corners[2] += 2;
708 corners[3]++;
709 corners[7] += 2;
710 corners[6]++;
711 } else if (m == 5) {
712 cycle(corners, 3, 0, 4, 7);
713 corners[3] += 2;
714 corners[0]++;
715 corners[4] += 2;
716 corners[7]++;
717 } else if (m == 1) {
718 cycle(corners, 3, 2, 1, 0);
719 } else if (m == 4) {
720 cycle(corners, 4, 5, 6, 7);
721 }
722 // convert back to number
723 return (ori2num(corners, 0, 8, 3));
724 }
725
726 private int gettransCornPerm(int pos, int m) {

Pagina 213 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

727 // convert pos number into permutation


728 int corners[] = new int[8];
729 num2perm(corners, 0, 8, pos);
730 // do move L U F R D B
731 if (m == 3) {
732 cycle(corners, 0, 1, 5, 4);
733 } else if (m == 2) {
734 cycle(corners, 1, 2, 6, 5);
735 } else if (m == 0) {
736 cycle(corners, 2, 3, 7, 6);
737 } else if (m == 5) {
738 cycle(corners, 3, 0, 4, 7);
739 } else if (m == 1) {
740 cycle(corners, 3, 2, 1, 0);
741 } else if (m == 4) {
742 cycle(corners, 4, 5, 6, 7);
743 }
744 // convert back to number
745 return (perm2num(corners, 0, 8));
746 }
747
748 private int gettransEdgePerm(int pos, int m) {
749 // convert pos number into permutation
750 int edges[] = new int[8];
751 num2perm(edges, 0, 8, pos);
752 // do move L U F R D B
753 if (m == 3) {
754 swap(edges, 0, 4);
755 } else if (m == 2) {
756 swap(edges, 1, 5);
757 } else if (m == 0) {
758 swap(edges, 2, 6);
759 } else if (m == 5) {
760 swap(edges, 3, 7);
761 } else if (m == 1) {
762 cycle(edges, 3, 2, 1, 0);
763 } else if (m == 4) {
764 cycle(edges, 4, 5, 6, 7);
765 }
766 // convert back to number
767 return (perm2num(edges, 0, 8));
768 }
769
770 private int gettransSliceFull(int pos, int m) {
771 int i, j, r;
772 // convert pos number into permutation
773 int edges[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
774 for (i = 0; i < 4; i++) {
775 r = pos % (12 - i);
776 pos = (pos - r) / (12 - i);
777 for (j = 0; j < 12 && (edges[j] != 0 || r > 0); j++) {
778 if (edges[j] == 0)
779 r--;
780 }
781 edges[j] = i + 1;
782 }
783
784 // do move L U F R D B
785 if (m == 3) {
786 cycle(edges, 0, 5, 8, 4);
787 } else if (m == 2) {
788 cycle(edges, 1, 6, 9, 5);
789 } else if (m == 0) {
790 cycle(edges, 2, 7, 10, 6);
791 } else if (m == 5) {
792 cycle(edges, 3, 4, 11, 7);

Pagina 214 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverKociemba

793 } else if (m == 1) {
794 cycle(edges, 3, 2, 1, 0);
795 } else if (m == 4) {
796 cycle(edges, 8, 9, 10, 11);
797 }
798 // convert back to number
799 pos = 0;
800 for (i = 3; i >= 0; i--) {
801 r = 0;
802 for (j = 0; j < 12 && edges[j] != i + 1; j++) {
803 if (edges[j] == 0 || edges[j] > i + 1)
804 r++;
805 }
806 pos = pos * (12 - i) + r;
807 }
808 return (pos);
809 }
810
811 private int gettransSlicePerm(int pos, int m) {
812 // convert pos number into permutation
813 int edges[] = new int[4];
814 num2perm(edges, 0, 4, pos);
815 // do move L U F R D B
816 if (m == 3) {
817 swap(edges, 0, 1);
818 } else if (m == 2) {
819 swap(edges, 1, 2);
820 } else if (m == 0) {
821 swap(edges, 2, 3);
822 } else if (m == 5) {
823 swap(edges, 3, 0);
824 }
825 // convert back to number
826 return (perm2num(edges, 0, 4));
827 }
828
829 private int gettransChoice(int pos, int m) {
830 // convert pos number into orientation
831 int edges[] = new int[12];
832 num2ori(edges, 0, 12, 2, pos);
833
834 // do move L U F R D B
835 if (m == 3) {
836 cycle(edges, 0, 5, 8, 4);
837 } else if (m == 2) {
838 cycle(edges, 1, 6, 9, 5);
839 } else if (m == 0) {
840 cycle(edges, 2, 7, 10, 6);
841 } else if (m == 5) {
842 cycle(edges, 3, 4, 11, 7);
843 } else if (m == 1) {
844 cycle(edges, 3, 2, 1, 0);
845 } else if (m == 4) {
846 cycle(edges, 8, 9, 10, 11);
847 }
848 // convert back to number
849 return (ori2num(edges, 0, 12, 2));
850 }
851 }

Pagina 215 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSlice

1 package solver.solverJS.algorithm;
2
3 // ----- Solver for the Slice group ----
4 import java.awt.event.*;
5
6 public final class SolverSlice extends Solver {
7 int maxdepth; // current search depth
8 byte prune[][][][];
9 byte prune2[][][][][];
10 final int transCorn[][] = { { 1, 5, 6, 2, 0, 4, 7, 3 }, // Ls
11 { 1, 2, 3, 0, 5, 6, 7, 4 }, // Us
12 { 4, 5, 1, 0, 7, 6, 2, 3 } };// Fs
13
14 final int transEdge[][] = { { 5, 1, 6, 3, 0, 8, 10, 2, 4, 9, 7, 11 }, // Ls
15 { 1, 2, 3, 0, 4, 5, 6, 7, 9, 10, 11, 8 }, // Us
16 { 0, 5, 2, 4, 11, 9, 1, 3, 8, 6, 10, 7 } };// Fs
17
18 int transOri[][];
19
20 public SolverSlice(ActionListener m) {
21 super(m);
22 }
23
24 public MoveSequence getGenerator() {
25 int[] m = new int[sollen];
26 int[] a = new int[sollen];
27 for (int i = 0; i < sollen; i++) {
28 m[i] = 12 + solmoves[i];
29 a[i] = solamount[i];
30 if (m[i] > 14) {
31 m[i] -= 3;
32 a[i] = 4 - a[i];
33 }
34 }
35 return (new MoveSequence(sollen, m, a));
36 }
37
38 public void mix(CubePosition cubePos) {
39 int j;
40 // direct method, not random moves
41 cubePos.reset();
42 // random position of corners
43 // choose one of the three axes to go UD
44 j = (int) (3 * Math.random());
45 if (j == 1) {
46 cubePos.doMove(0);
47 cubePos.doMove(3);
48 cubePos.doMove(3);
49 cubePos.doMove(3);
50 } else if (j == 2) {
51 cubePos.doMove(2);
52 cubePos.doMove(5);
53 cubePos.doMove(5);
54 cubePos.doMove(5);
55 }
56 // maybe swap over UD axis
57 j = (int) (2 * Math.random());
58 if (j != 0) {
59 cubePos.doMove(0);
60 cubePos.doMove(0);
61 cubePos.doMove(3);
62 cubePos.doMove(3);
63 }
64 // rotate around UD axis
65 j = (int) (4 * Math.random());
66 while (j > 0) {

Pagina 216 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSlice

67 cubePos.doMove(1);
68 cubePos.doMove(4);
69 cubePos.doMove(4);
70 cubePos.doMove(4);
71 j--;
72 }
73
74 // now mix edges
75 j = (int) (4 * Math.random());
76 while (j > 0) {
77 // two 4-cycles of slice edges
78 cubePos.doMove(0);
79 cubePos.doMove(3);
80 cubePos.doMove(3);
81 cubePos.doMove(3);
82 cubePos.doMove(1);
83 cubePos.doMove(4);
84 cubePos.doMove(4);
85 cubePos.doMove(4);
86 cubePos.doMove(2);
87 cubePos.doMove(5);
88 cubePos.doMove(5);
89 cubePos.doMove(5);
90 cubePos.doMove(4);
91 cubePos.doMove(1);
92 cubePos.doMove(1);
93 cubePos.doMove(1);
94 j--;
95 }
96 j = (int) (4 * Math.random());
97 while (j > 0) {
98 // two 4-cycles of slice edges
99 cubePos.doMove(1);
100 cubePos.doMove(4);
101 cubePos.doMove(4);
102 cubePos.doMove(4);
103 cubePos.doMove(2);
104 cubePos.doMove(5);
105 cubePos.doMove(5);
106 cubePos.doMove(5);
107 cubePos.doMove(0);
108 cubePos.doMove(3);
109 cubePos.doMove(3);
110 cubePos.doMove(3);
111 cubePos.doMove(2);
112 cubePos.doMove(2);
113 cubePos.doMove(2);
114 cubePos.doMove(5);
115 j--;
116 }
117 j = (int) (2 * Math.random());
118 if (j != 0) {
119 // 4-H pattern
120 swap(cubePos.cubeletPerm, 12, 14);
121 swap(cubePos.cubeletPerm, 13, 15);
122 }
123 // do face centres
124 j = (int) (4 * Math.random());
125 cubePos.cubeletOri[20] = j;
126 cubePos.cubeletOri[23] = (4 - j) & 3;
127 j = (int) (4 * Math.random());
128 cubePos.cubeletOri[21] = j;
129 cubePos.cubeletOri[24] = (4 - j) & 3;
130 j = (int) (2 * Math.random());
131 cubePos.cubeletOri[22] = j + j;
132 if (cubePos.cubeletPerm[1] == 0 || cubePos.cubeletPerm[3] == 0

Pagina 217 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSlice

133 || cubePos.cubeletPerm[4] == 0 || cubePos.cubeletPerm[6] == 0) {


134 cubePos.cubeletOri[22] ^= 1;
135 }
136 if (((cubePos.cubeletOri[20] + cubePos.cubeletOri[21]) & 1) != 0) {
137 cubePos.cubeletOri[22] ^= 1;
138 }
139 cubePos.cubeletOri[25] = (4 - cubePos.cubeletOri[22]) & 3;
140 }
141
142 public boolean setPosition(CubePosition cubePos, boolean test) {
143 int i, j;
144
145 // check corner orientation
146 for (i = 0; i < 7; i++) {
147 if (i == 3) {
148 j = cubePos.cubeletOri[0] + cubePos.cubeletOri[4];
149 } else {
150 j = cubePos.cubeletOri[i] + cubePos.cubeletOri[i + 1];
151 }
152 if (j != 0 && j != 3)
153 return (false);
154 }
155
156 // check edge orientation
157 if (cubePos.cubeletOri[8] != cubePos.cubeletOri[10]
158 || cubePos.cubeletOri[8] != cubePos.cubeletOri[16]
159 || cubePos.cubeletOri[8] != cubePos.cubeletOri[18])
160 return (false);
161 if (cubePos.cubeletOri[9] != cubePos.cubeletOri[11]
162 || cubePos.cubeletOri[9] != cubePos.cubeletOri[17]
163 || cubePos.cubeletOri[9] != cubePos.cubeletOri[19])
164 return (false);
165 if (cubePos.cubeletOri[12] != cubePos.cubeletOri[13]
166 || cubePos.cubeletOri[12] != cubePos.cubeletOri[14]
167 || cubePos.cubeletOri[12] != cubePos.cubeletOri[15])
168 return (false);
169
170 // check face centre orientation
171 if (cubieSettings.superGroup) {
172 for (i = 0; i < 3; i++) {
173 if (((cubePos.cubeletOri[20 + i] + cubePos.cubeletOri[23 + i]) & 3) != 0)
174 return (false);
175 }
176 if (cubePos.cubeletPerm[1] == 0 || cubePos.cubeletPerm[3] == 0
177 || cubePos.cubeletPerm[4] == 0 || cubePos.cubeletPerm[6] == 0) {
178 if (((cubePos.cubeletOri[20] + cubePos.cubeletOri[21]
179 + cubePos.cubeletOri[22])
180 & 1) == 0)
181 return (false);
182 } else {
183 if (((cubePos.cubeletOri[20] + cubePos.cubeletOri[21]
184 + cubePos.cubeletOri[22])
185 & 1) != 0)
186 return (false);
187 }
188 }
189
190 // first copy array
191 int perm[] = new int[20];
192 int ori[] = new int[3];
193 for (i = 0; i < 20; i++) {
194 perm[i] = cubePos.cubeletPerm[i];
195 }
196 ori[0] = cubePos.cubeletOri[8];
197 ori[1] = cubePos.cubeletOri[9];
198 ori[2] = cubePos.cubeletOri[12];

Pagina 218 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSlice

199
200 // solve corners
201 // align UD axis
202 if (cubePos.cubeletOri[0] == 1) { // do Fs'
203 cycle(perm, 0, 4, 7, 3);
204 cycle(perm, 1, 5, 6, 2);
205 cycle(perm, 9, 13, 17, 14);
206 cycle(perm, 11, 12, 19, 15);
207 swap(ori, 1, 2);
208 } else if (cubePos.cubeletOri[0] == 2) { // do Rs'
209 cycle(perm, 0, 1, 5, 4);
210 cycle(perm, 3, 2, 6, 7);
211 cycle(perm, 8, 13, 16, 12);
212 cycle(perm, 10, 14, 18, 15);
213 i = ori[0];
214 ori[0] = 1 - ori[2];
215 ori[2] = 1 - i;
216 }
217 // flip UD axis if necessary to bring 0 up
218 if (perm[4] == 0 || perm[5] == 0 || perm[6] == 0 || perm[7] == 0) {
219 // do Fs2
220 swap(perm, 0, 7);
221 swap(perm, 4, 3);
222 swap(perm, 1, 6);
223 swap(perm, 5, 2);
224 swap(perm, 11, 19);
225 swap(perm, 12, 15);
226 swap(perm, 9, 17);
227 swap(perm, 13, 14);
228 }
229 // turn 0 into position
230 while (perm[0] != 0) { // do Us'
231 cycle(perm, 0, 1, 2, 3);
232 cycle(perm, 4, 5, 6, 7);
233 cycle(perm, 8, 9, 10, 11);
234 cycle(perm, 16, 17, 18, 19);
235 swap(ori, 0, 1);
236 }
237 // corners should be solved now.
238 for (i = 0; i < 8; i++)
239 if (perm[i] != i)
240 return (false);
241
242 // solve LR slice
243 if (perm[9] != 9 && perm[11] != 9 && perm[17] != 9 && perm[19] != 9)
244 return (false);
245 while (perm[9] != 9) {
246 cycle(perm, 9, 17, 19, 11);
247 cycle(perm, 12, 13, 14, 15);
248 ori[1] = 1 - ori[1];
249 ori[2] = 1 - ori[2];
250 }
251 if (ori[1] != 0 || perm[11] != 11 || perm[17] != 17 || perm[19] != 19)
252 return (false);
253 // solve FB slice
254 if (perm[8] != 8 && perm[10] != 8 && perm[16] != 8 && perm[18] != 8)
255 return (false);
256 while (perm[8] != 8) {
257 cycle(perm, 8, 16, 18, 10);
258 cycle(perm, 12, 13, 14, 15);
259 ori[0] = 1 - ori[0];
260 ori[2] = 1 - ori[2];
261 }
262 if (ori[0] != 0 || perm[10] != 10 || perm[16] != 16 || perm[18] != 18)
263 return (false);
264 // solve UD slice

Pagina 219 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSlice

265 if (perm[14] == 12) {


266 swap(perm, 12, 14);
267 swap(perm, 13, 15);
268 }
269 if (ori[2] != 0 || perm[12] != 12 || perm[13] != 13 || perm[14] != 14
270 || perm[15] != 15)
271 return (false);
272
273 if (test)
274 return (true);
275 if (!prepared)
276 return (false);
277
278 // convert to numbers. Use one corner and one representative from each slice
279 for (i = 0; i < 8; i++) {
280 if (cubePos.cubeletPerm[i] == 0)
281 perm[0] = i;
282 }
283 for (i = 8; i < 20; i++) {
284 if (cubePos.cubeletPerm[i] == 8)
285 perm[1] = i - 8;
286 else if (cubePos.cubeletPerm[i] == 9)
287 perm[2] = i - 8;
288 else if (cubePos.cubeletPerm[i] == 12)
289 perm[3] = i - 8;
290 }
291 // store face orientation
292 perm[4] = (cubePos.cubeletOri[20] << 4) + (cubePos.cubeletOri[21] << 2)
293 + cubePos.cubeletOri[22];
294
295 if (positionlist == null) {
296 positionlist = new int[40][5];
297 maxdepth = sollen = 0;
298 solmoves[0] = -1;
299 solamount[0] = 3;
300 } else if (positionlist[0][0] != perm[0] || positionlist[0][1] != perm[1]
301 || positionlist[0][2] != perm[2] || positionlist[0][3] != perm[3]
302 || (positionlist[0][4] != perm[4] && cubieSettings.superGroup)) {
303 // clear out search history
304 maxdepth = sollen = 0;
305 solmoves[0] = -1;
306 solamount[0] = 3;
307 }
308 // set position
309 positionlist[0][0] = perm[0];
310 positionlist[0][1] = perm[1];
311 positionlist[0][2] = perm[2];
312 positionlist[0][3] = perm[3];
313 positionlist[0][4] = perm[4];
314 return (true);
315 }
316
317 // initialise tables
318 protected void init() {
319 int i1, i2, i3, i4, i5, k, m, q, j1, j2, j3, j4, j5;
320 prune = new byte[8][12][12][12];
321 prune2 = new byte[8][12][12][12][64];
322 transOri = new int[64][3];
323
324 // calculate transition table for the face centres
325 k = 0;
326 for (i1 = 0; i1 < 4; i1++)
327 for (i2 = 0; i2 < 4; i2++)
328 for (i3 = 0; i3 < 4; i3++) {
329 transOri[k][0] = (((i1 + 3) & 3) << 4) + (i2 << 2) + i3;
330 transOri[k][1] = (i1 << 4) + (((i2 + 3) & 3) << 2) + i3;

Pagina 220 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSlice

331 transOri[k][2] = (i1 << 4) + (i2 << 2) + ((i3 + 3) & 3);


332 k++;
333 }
334
335 // calculate pruning tables
336 int l = 1;
337 prune[0][0][1][4] = 1;
338 do {
339 k = 0;
340 for (i1 = 0; i1 < 8; i1++)
341 for (i2 = 0; i2 < 12; i2++)
342 for (i3 = 0; i3 < 12; i3++)
343 for (i4 = 0; i4 < 12; i4++) {
344 if (prune[i1][i2][i3][i4] == l) {
345 for (m = 0; m < 3; m++) {
346 j1 = i1;
347 j2 = i2;
348 j3 = i3;
349 j4 = i4;
350 for (q = 0; q < 3; q++) {
351 j1 = transCorn[m][j1];
352 j2 = transEdge[m][j2];
353 j3 = transEdge[m][j3];
354 j4 = transEdge[m][j4];
355 if (prune[j1][j2][j3][j4] == 0) {
356 prune[j1][j2][j3][j4] = (byte) (l + 1);
357 k++;
358 }
359 }
360 }
361 }
362 }
363 l++;
364 } while (k != 0);
365
366 // calculate pruning tables
367 l = 1;
368 prune2[0][0][1][4][0] = 1;
369 do {
370 k = 0;
371 for (i1 = 0; i1 < 8; i1++)
372 for (i2 = 0; i2 < 12; i2++)
373 for (i3 = 0; i3 < 12; i3++)
374 for (i4 = 0; i4 < 12; i4++)
375 for (i5 = 0; i5 < 64; i5++) {
376 if (prune2[i1][i2][i3][i4][i5] == l) {
377 for (m = 0; m < 3; m++) {
378 j1 = i1;
379 j2 = i2;
380 j3 = i3;
381 j4 = i4;
382 j5 = i5;
383 for (q = 0; q < 3; q++) {
384 j1 = transCorn[m][j1];
385 j2 = transEdge[m][j2];
386 j3 = transEdge[m][j3];
387 j4 = transEdge[m][j4];
388 j5 = transOri[j5][m];
389 if (prune2[j1][j2][j3][j4][j5] == 0) {
390 prune2[j1][j2][j3][j4][j5] = (byte) (l + 1);
391 k++;
392 }
393 }
394 }
395 }
396 }

Pagina 221 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSlice

397 l++;
398 } while (k != 0);
399
400 }
401
402 // solve a position
403 protected boolean solve() {
404 // do IDA* - search depth first for each maxdepth.
405 while (!search()) {
406 if (wanttostop)
407 return (false);
408 maxdepth++;
409 }
410 return (true);
411 }
412
413 private boolean search() {
414 // do a depth search through all positions at depth maxdepth.
415 // return false if no solution, or break out with true if solved.
416 int m, nxt;
417
418 // do check for solved position with null solution.
419 if (maxdepth == 0 && sollen == 0 && positionlist[0][0] == 0
420 && positionlist[0][1] == 0
421 && positionlist[0][2] == 1 && positionlist[0][3] == 4
422 && (!cubieSettings.superGroup || positionlist[0][4] == 0))
423 return (true);
424
425 while (sollen >= 0) {
426 // at this point positionlist[0..sollen] are visited positions
427 // and solmoves[0..sollen-1] are moves performed.
428 // Note solmoves[sollen] is last tried (rejected) next move
429 nxt = sollen + 1;
430 // add extra quarter turn to last move
431 m = solmoves[sollen];
432 if (m >= 0) { // ignore dummy -1 move
433 positionlist[nxt][0] = transCorn[m][positionlist[nxt][0]];
434 positionlist[nxt][1] = transEdge[m][positionlist[nxt][1]];
435 positionlist[nxt][2] = transEdge[m][positionlist[nxt][2]];
436 positionlist[nxt][3] = transEdge[m][positionlist[nxt][3]];
437 if (cubieSettings.superGroup) {
438 positionlist[nxt][4] = transOri[positionlist[nxt][4]][m];
439 }
440 } else {
441 positionlist[nxt][0] = positionlist[sollen][0];
442 positionlist[nxt][1] = positionlist[sollen][1];
443 positionlist[nxt][2] = positionlist[sollen][2];
444 positionlist[nxt][3] = positionlist[sollen][3];
445 positionlist[nxt][4] = positionlist[sollen][4];
446 }
447 solamount[sollen]++;
448 // if done full turn, then move to next face
449 if (solamount[sollen] > 3) {
450 // next face, 0 turns yet
451 solamount[sollen] = 0;
452 do {
453 solmoves[sollen]++;
454 } while (sollen != 0 && solmoves[sollen] == solmoves[sollen - 1]);
455 if (solmoves[sollen] >= 3) {
456 // done all faces. backtrack
457 sollen--;
458 continue;
459 }
460 continue; // loop back to do a quarter turn of this new face
461 }
462

Pagina 222 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSlice

463 // check pruning for proposed new position


464 if ((cubieSettings.superGroup || sollen
465 + prune[positionlist[nxt][0]][positionlist[nxt][1]]
466 [positionlist[nxt][2]][positionlist[nxt][3]] < maxdepth
467 + 1)
468 && (!cubieSettings.superGroup || sollen
469 + prune2[positionlist[nxt][0]][positionlist[nxt][1]]
470 [positionlist[nxt][2]][positionlist[nxt][3]]
471 [positionlist[nxt][4]] < maxdepth
472 + 1)) {
473 // its ok, officially add to movelist
474 // append dummy move to list for later extension.
475 solmoves[nxt] = -1;
476 solamount[nxt] = 3;
477 sollen = nxt;
478 // check if have found solution of required length;
479 if (sollen >= maxdepth)
480 return (true);
481 }
482
483 if (wanttostop)
484 return (false);
485 // loop back to shift to next move sequence
486 }
487 // reset for next search
488 solmoves[0] = -1;
489 solamount[0] = 3;
490 sollen = 0;
491 return (false);
492 }
493 }

Pagina 223 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

1 package solver.solverJS.algorithm;
2
3 // ----- Solver for the Square group ----
4 import java.awt.event.*;
5
6 public final class SolverSquare extends Solver {
7 int transEdge[][][];
8 int transCorn[][];
9 int transCorn2[][];
10 byte pruneEdge[][][];
11 byte pruneCorn[];
12 byte pruneCorn2[];
13 int maxdepth; // current search depth
14 final int orbits[][] = {
15 // UR,DR,DL,UL RB,RF,LF,LB UF,DF,DB,UB
16 { 8, 16, 18, 10 }, { 12, 13, 14, 15 }, { 9, 17, 19, 11 },
17 // UBR,UFL,DFR,DBL, URF,ULB,DRB,DLF
18 { 0, 2, 5, 7 }, { 1, 3, 4, 6 } };
19
20 public SolverSquare(ActionListener m) {
21 super(m);
22 }
23
24 public MoveSequence getGenerator() {
25 int[] a = new int[sollen];
26 for (int i = 0; i < sollen; i++) {
27 a[i] = 2;
28 }
29 return (new MoveSequence(sollen, solmoves, a));
30 }
31
32 public void mix(CubePosition cubePos) {
33 int i, j;
34 // direct method, not random moves
35 cubePos.reset();
36 // put random corner at position 2
37 j = (int) (4 * Math.random());
38 if (j != 3) {
39 cubePos.doMove(j);
40 cubePos.doMove(j);
41 }
42 // put random corner at 5
43 j = (int) (3 + 3 * Math.random());
44 if (j != 5) {
45 cubePos.doMove(j);
46 cubePos.doMove(j);
47 }
48 // put random corner at 0/7
49 j = (int) (2 * Math.random());
50 if (j != 0) {
51 cubePos.doMove(5);
52 cubePos.doMove(5);
53 }
54 // randomly twist other tetrad
55 j = (int) (4 * Math.random());
56 if (j == 0) {
57 cubePos.doMove(2);
58 cubePos.doMove(2);
59 cubePos.doMove(3);
60 cubePos.doMove(3);
61 cubePos.doMove(1);
62 cubePos.doMove(1);
63 cubePos.doMove(3);
64 cubePos.doMove(3);
65 } else if (j == 1) {
66 cubePos.doMove(3);

Pagina 224 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

67 cubePos.doMove(3);
68 cubePos.doMove(1);
69 cubePos.doMove(1);
70 cubePos.doMove(2);
71 cubePos.doMove(2);
72 cubePos.doMove(1);
73 cubePos.doMove(1);
74 } else if (j == 2) {
75 cubePos.doMove(1);
76 cubePos.doMove(1);
77 cubePos.doMove(2);
78 cubePos.doMove(2);
79 cubePos.doMove(3);
80 cubePos.doMove(3);
81 cubePos.doMove(2);
82 cubePos.doMove(2);
83 }
84 // corners are now in place.
85 // randomly place edges
86 int order[] = new int[4];
87 for (i = 0; i < 3; i++) {
88 num2perm(order, 0, 4, (int) (4 * Math.random()));
89 for (j = 0; j < 4; j++) {
90 cubePos.cubeletPerm[orbits[i][j]] = orbits[i][order[j]];
91 }
92 }
93 // ensure edges have even permutation
94 if (parityOdd(cubePos.cubeletPerm, 8, 12)) {
95 // swap two edges to fix it.
96 swap(cubePos.cubeletPerm, 8, 10);
97 }
98
99 // convert orbits
100 int perm[] = new int[20];
101 int k, c = 0;
102 for (i = 0; i < 5; i++) {
103 for (j = 0; j < 4; j++) {
104 for (k = 0; k < 4; k++) {
105 if (cubePos.cubeletPerm[orbits[i][j]] == orbits[i][k])
106 break;
107 }
108 perm[c++] = k;
109 }
110 }
111
112 // do face centres. First ensure solvable
113 j = 0;// 210:LUF
114 for (i = 0; i < 6; i++)
115 cubePos.cubeletOri[20 + i] = 0;
116 if (parityOdd(perm, 12, 4))
117 j ^= 7;
118 if (parityOdd(perm, 0, 4))
119 j ^= 6;
120 if (parityOdd(perm, 4, 4))
121 j ^= 5;
122 if (parityOdd(perm, 8, 4))
123 j ^= 3;
124 if ((j & 4) != 0)
125 cubePos.cubeletOri[20] = 2;
126 if ((j & 2) != 0)
127 cubePos.cubeletOri[21] = 2;
128 if ((j & 1) != 0)
129 cubePos.cubeletOri[22] = 2;
130
131 // randomize face centres
132 j = (int) (8 * Math.random());

Pagina 225 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

133 if ((j & 4) != 0) {


134 cubePos.cubeletOri[20] ^= 2;
135 cubePos.cubeletOri[23] ^= 2;
136 }
137 if ((j & 2) != 0) {
138 cubePos.cubeletOri[21] ^= 2;
139 cubePos.cubeletOri[24] ^= 2;
140 }
141 if ((j & 1) != 0) {
142 cubePos.cubeletOri[22] ^= 2;
143 cubePos.cubeletOri[25] ^= 2;
144 }
145 }
146
147 public boolean setPosition(CubePosition cubePos, boolean test) {
148 int i, j, k, c;
149 int perm[] = new int[20];
150
151 if (parityOdd(cubePos.cubeletPerm, 0, 20))
152 return (false);
153
154 // check orientations
155 for (i = 0; i < 20; i++) {
156 if (cubePos.cubeletOri[i] != 0)
157 return (false);
158 }
159 // check and convert orbits
160 c = 0;
161 for (i = 0; i < 5; i++) {
162 for (j = 0; j < 4; j++) {
163 for (k = 0; k < 4; k++) {
164 if (cubePos.cubeletPerm[orbits[i][j]] == orbits[i][k])
165 break;
166 }
167 if (k >= 4)
168 return (false);
169 perm[c++] = k;
170 }
171 }
172 // corner (and total edge) perm must be even
173 if (parityOdd(perm, 12, 4) != parityOdd(perm, 16, 4))
174 return (false);
175
176 // check face centres
177 if (cubieSettings.superGroup) {
178 // must be half turns
179 for (i = 0; i < 6; i++) {
180 if ((cubePos.cubeletOri[20 + i] & 1) != 0)
181 return (false);
182 }
183 // UR,DR,DL,UL RB,RF,LF,LB UF,DF,DB,UB
184 j = 0;// 210:LUF
185 if (parityOdd(perm, 12, 4))
186 j ^= 7;
187 if (parityOdd(perm, 0, 4))
188 j ^= 6;
189 if (parityOdd(perm, 4, 4))
190 j ^= 5;
191 if (parityOdd(perm, 8, 4))
192 j ^= 3;
193 if (cubePos.cubeletOri[20] != cubePos.cubeletOri[23])
194 j ^= 4;
195 if (cubePos.cubeletOri[21] != cubePos.cubeletOri[24])
196 j ^= 2;
197 if (cubePos.cubeletOri[22] != cubePos.cubeletOri[25])
198 j ^= 1;

Pagina 226 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

199 if (j != 0)
200 return (false);
201 }
202
203 // convert to numbers
204 int newpos[] = new int[4];
205 newpos[0] = perm2num(perm, 0, 4);
206 newpos[1] = perm2num(perm, 4, 4);
207 newpos[2] = perm2num(perm, 8, 4);
208 newpos[3] = perm2num(perm, 12, 4);
209 for (k = 0; k < 4; k++) {
210 if (cubePos.cubeletPerm[orbits[4][k]] == orbits[4][0])
211 break;
212 }
213 newpos[3] = newpos[3] * 4 + k;
214 if (cubieSettings.superGroup) {
215 j = 0;
216 if (cubePos.cubeletOri[20] != 0)
217 j ^= 4;
218 if (cubePos.cubeletOri[21] != 0)
219 j ^= 2;
220 if (cubePos.cubeletOri[22] != 0)
221 j ^= 1;
222 newpos[3] = (newpos[3] << 3) + j;
223 }
224
225 // do permutations to solve corners.
226
227 // solve corner 0 of first orbit
228 if (perm[13] == 0) {
229 swap(perm, 12, 13);
230 swap(perm, 14, 15);
231
232 } else if (perm[14] == 0) {
233 swap(perm, 12, 14);
234 swap(perm, 13, 15);
235 } else if (perm[15] == 0) {
236 swap(perm, 12, 15);
237 swap(perm, 13, 14);
238 }
239 // solve corner 1 of first orbit
240 if (perm[14] == 1) { // F
241 swap(perm, 13, 14);
242 swap(perm, 16, 19);
243 } else if (perm[15] == 1) { // L
244 swap(perm, 13, 15);
245 swap(perm, 17, 19);
246 }
247 // solve corners 2,3 of first orbit
248 // UBR,UFL,DFR,DBL, URF,ULB,DRB,DLF
249 if (perm[15] == 2) { // D
250 swap(perm, 14, 15);
251 swap(perm, 18, 19);
252 }
253 // solve corners 0 of second orbit
254 // UBR,UFL,DFR,DBL, URF,ULB,DRB,DLF
255 if (perm[17] == 0) {
256 swap(perm, 16, 17);
257 swap(perm, 18, 19);
258 } else if (perm[18] == 0) {
259 swap(perm, 16, 18);
260 swap(perm, 17, 19);
261 } else if (perm[19] == 0) {
262 swap(perm, 16, 19);
263 swap(perm, 17, 18);
264 }

Pagina 227 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

265 if (perm[17] != 1 || perm[18] != 2 || perm[19] != 3)


266 return (false);
267
268 if (test)
269 return (true);
270 if (!prepared)
271 return (false);
272
273 if (positionlist == null) {
274 positionlist = new int[40][4];
275 maxdepth = sollen = 0;
276 solmoves[0] = -1;
277 solamount[0] = 3;
278 } else if (positionlist[0][0] != newpos[0] || positionlist[0][1] != newpos[1]
279 || positionlist[0][2] != newpos[2] || positionlist[0][3] != newpos[3]) {
280 // clear out search history
281 maxdepth = sollen = 0;
282 solmoves[0] = -1;
283 solamount[0] = 3;
284 }
285 // set position
286 positionlist[0][0] = newpos[0];
287 positionlist[0][1] = newpos[1];
288 positionlist[0][2] = newpos[2];
289 positionlist[0][3] = newpos[3];
290 return (true);
291 }
292
293 protected boolean solve() {
294 // do IDA* - search depth first for each maxdepth.
295 while (!search()) {
296 if (wanttostop)
297 return (false);
298 maxdepth++;
299 }
300 return (true);
301 }
302
303 private boolean search() {
304 // do a depth search through all positions at depth maxdepth.
305 // return false if no solution, or break out with true if solved.
306 int m, nxt;
307
308 // do check for solved position with null solution.
309 if (maxdepth == 0 && sollen == 0
310 && positionlist[0][0] == 0 && positionlist[0][1] == 0
311 && positionlist[0][2] == 0 && positionlist[0][3] == 0)
312 return (true);
313
314 while (sollen >= 0) {
315 // at this point positionlist[0..sollen] are visited positions
316 // and solmoves[0..sollen-1] are moves performed.
317 // Note solmoves[sollen] is last tried (rejected) next move
318 nxt = sollen + 1;
319 // add extra half turn to last move
320 m = solmoves[sollen];
321 if (m >= 0) { // ignore dummy -1 move
322 positionlist[nxt][0] = transEdge[0][positionlist[nxt][0]][m];
323 positionlist[nxt][1] = transEdge[1][positionlist[nxt][1]][m];
324 positionlist[nxt][2] = transEdge[2][positionlist[nxt][2]][m];
325 if (cubieSettings.superGroup) {
326 positionlist[nxt][3] = transCorn2[positionlist[nxt][3]][m];
327 } else {
328 positionlist[nxt][3] = transCorn[positionlist[nxt][3]][m];
329 }
330 } else {

Pagina 228 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

331 positionlist[nxt][0] = positionlist[sollen][0];


332 positionlist[nxt][1] = positionlist[sollen][1];
333 positionlist[nxt][2] = positionlist[sollen][2];
334 positionlist[nxt][3] = positionlist[sollen][3];
335 }
336 solamount[sollen] += 2;
337 // if done full turn, then move to next face
338 if (solamount[sollen] > 3) {
339 // next face, 0 turns yet
340 solamount[sollen] = 0;
341 do {
342 solmoves[sollen]++;
343 } while (sollen != 0 && (solmoves[sollen] == solmoves[sollen - 1]
344 || solmoves[sollen] == solmoves[sollen - 1] + 3));
345 if (solmoves[sollen] >= 6) {
346 // done all faces. backtrack
347 sollen--;
348 continue;
349 }
350 continue; // loop back to do a quarter turn of this new face
351 }
352
353 // check pruning for proposed new position
354 if (sollen
355 + pruneEdge[positionlist[nxt][0]][positionlist[nxt][1]]
356 [positionlist[nxt][2]] < maxdepth
357 + 1
358 && (cubieSettings.superGroup
359 || sollen + pruneCorn[positionlist[nxt][3]] < maxdepth + 1)
360 && (!cubieSettings.superGroup
361 || sollen + pruneCorn2[positionlist[nxt][3]] < maxdepth + 1)) {
362 // its ok, officially add to movelist
363 // append dummy move to list for later extension.
364 solmoves[nxt] = -1;
365 solamount[nxt] = 3;
366 sollen = nxt;
367 // check if have found solution of required length;
368 if (sollen >= maxdepth)
369 return (true);
370 }
371
372 if (wanttostop)
373 return (false);
374 // loop back to shift to next move sequence
375 }
376 // reset for next search
377 solmoves[0] = -1;
378 solamount[0] = 3;
379 sollen = 0;
380 return (false);
381 }
382
383 // initialise tables
384 protected void init() {
385 int i, k, m;
386 transEdge = new int[3][24][6];
387 transCorn = new int[96][6];
388 transCorn2 = new int[768][6];
389 pruneEdge = new byte[24][24][24];
390 pruneCorn = new byte[96];
391 pruneCorn2 = new byte[768];
392 for (k = 0; k < 3; k++) { // each slice
393 for (i = 0; i < 24; i++) { // each edge position
394 for (m = 0; m < 6; m++) { // each move
395 transEdge[k][i][m] = gettransEdge(k, i, m);
396 }

Pagina 229 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

397 }
398 }
399 for (i = 0; i < 96; i++) { // each corner position
400 for (m = 0; m < 6; m++) { // each move
401 transCorn[i][m] = gettransCorn(i, m);
402 }
403 }
404 for (i = 0; i < 768; i++) { // each corner position
405 for (m = 0; m < 6; m++) { // each move
406 transCorn2[i][m] = gettransCorn2(i, m);
407 }
408 }
409
410 // calculate pruning tables. First corners
411 int l = 1;
412 pruneCorn[0] = 1;
413 do {
414 k = 0;
415 for (i = 0; i < 96; i++) {
416 if (pruneCorn[i] == l) {
417 for (m = 0; m < 6; m++) {
418 if (pruneCorn[transCorn[i][m]] == 0) {
419 pruneCorn[transCorn[i][m]] = (byte) (l + 1);
420 k++;
421 }
422 }
423 }
424 }
425 l++;
426 } while (k != 0);
427 // calculate pruning tables. First corners
428 l = 1;
429 pruneCorn2[0] = 1;
430 do {
431 k = 0;
432 for (i = 0; i < 768; i++) {
433 if (pruneCorn2[i] == l) {
434 for (m = 0; m < 6; m++) {
435 if (pruneCorn2[transCorn2[i][m]] == 0) {
436 pruneCorn2[transCorn2[i][m]] = (byte) (l + 1);
437 k++;
438 }
439 }
440 }
441 }
442 l++;
443 } while (k != 0);
444
445 // Now edge pruning table
446 l = 1;
447 int i2, i3;
448 pruneEdge[0][0][0] = 1;
449 do {
450 k = 0;
451 for (i = 0; i < 24; i++) {
452 for (i2 = 0; i2 < 24; i2++) {
453 for (i3 = 0; i3 < 24; i3++) {
454 if (pruneEdge[i][i2][i3] == l) {
455 for (m = 0; m < 6; m++) {
456 if (pruneEdge[transEdge[0][i][m]][transEdge[1][i2][m]]
457 [transEdge[2][i3][m]] == 0) {
458 pruneEdge[transEdge[0][i][m]][transEdge[1][i2][m]]
459 [transEdge[2][i3][m]] = (byte) (l + 1);
460 k++;
461 }
462 }

Pagina 230 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

463 }
464 }
465 }
466 }
467 l++;
468 } while (k != 0);
469 }
470
471 private int gettransEdge(int slice, int pos, int m) {
472 // convert pos number into permutation
473 // UR,DR,DL,UL RB,RF,LF,LB UF,DF,DB,UB
474 int edges[] = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 };
475 num2perm(edges, slice * 4, 4, pos);
476 // do move L U F R D B Lc Uc Fc
477 if (m == 0) {
478 swap(edges, 2, 3);
479 swap(edges, 6, 7);
480 } else if (m == 1) {
481 swap(edges, 0, 3);
482 swap(edges, 8, 11);
483 } else if (m == 2) {
484 swap(edges, 5, 6);
485 swap(edges, 8, 9);
486 } else if (m == 3) {
487 swap(edges, 0, 1);
488 swap(edges, 4, 5);
489 } else if (m == 4) {
490 swap(edges, 1, 2);
491 swap(edges, 9, 10);
492 } else if (m == 5) {
493 swap(edges, 4, 7);
494 swap(edges, 10, 11);
495 }
496 // convert back to number
497 return (perm2num(edges, slice * 4, 4));
498 }
499
500 private int gettransCorn(int pos, int m) {
501 // convert pos number into permutation
502 // UBR,UFL,DFR,DBL, URF,ULB,DRB,DLF
503 int corners[] = { 0, 1, 2, 3, 0, 0, 0, 0 };
504 num2perm(corners, 0, 4, pos >> 2);
505 corners[4 + (pos & 3)] = 1;
506 // do move L U F R D B Lc Uc Fc
507 if (m == 0) {
508 swap(corners, 1, 3);
509 swap(corners, 5, 7);
510 } else if (m == 1) {
511 swap(corners, 0, 1);
512 swap(corners, 4, 5);
513 } else if (m == 2) {
514 swap(corners, 1, 2);
515 swap(corners, 4, 7);
516 } else if (m == 3) {
517 swap(corners, 0, 2);
518 swap(corners, 4, 6);
519 } else if (m == 4) {
520 swap(corners, 2, 3);
521 swap(corners, 6, 7);
522 } else if (m == 5) {
523 swap(corners, 0, 3);
524 swap(corners, 5, 6);
525 }
526 // convert back to number
527 return (perm2num(corners, 0, 4) * 4 + corners[5]
528 + corners[6] * 2 + corners[7] * 3);

Pagina 231 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverSquare

529 }
530
531 private int gettransCorn2(int pos, int m) {
532 int c;
533 // convert pos number into permutation
534 // UBR,UFL,DFR,DBL, URF,ULB,DRB,DLF
535 int corners[] = { 0, 1, 2, 3, 0, 0, 0, 0 };
536 num2perm(corners, 0, 4, pos >> 5);
537 corners[4 + ((pos >> 3) & 3)] = 1;
538 c = pos & 7;
539 // do move L U F R D B Lc Uc Fc
540 if (m == 0) {
541 swap(corners, 1, 3);
542 swap(corners, 5, 7);
543 c ^= 4;
544 } else if (m == 1) {
545 swap(corners, 0, 1);
546 swap(corners, 4, 5);
547 c ^= 2;
548 } else if (m == 2) {
549 swap(corners, 1, 2);
550 swap(corners, 4, 7);
551 c ^= 1;
552 } else if (m == 3) {
553 swap(corners, 0, 2);
554 swap(corners, 4, 6);
555 } else if (m == 4) {
556 swap(corners, 2, 3);
557 swap(corners, 6, 7);
558 } else if (m == 5) {
559 swap(corners, 0, 3);
560 swap(corners, 5, 6);
561 }
562 // convert back to number
563 return ((perm2num(corners, 0, 4) << 5)
564 + ((corners[5] + corners[6] * 2 + corners[7] * 3) << 3) + c);
565 }
566 }

Pagina 232 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverTwoGen

1 package solver.solverJS.algorithm;
2
3 // ----- Solver for the Two-Generator group ----
4 import java.awt.event.*;
5
6 public final class SolverTwoGen extends Solver {
7 int maxdepth; // current search depth
8 int transCorn[][];
9 int transEdge[][];
10 int transOri[][];
11 int transOri2[][];
12 byte pruneCorn[];
13 byte pruneEdge[];
14 byte pruneOri[];
15 byte pruneOri2[];
16
17 public SolverTwoGen(ActionListener m) {
18 super(m);
19 }
20
21 public MoveSequence getGenerator() {
22 int[] m = new int[sollen];
23 for (int i = 0; i < sollen; i++) {
24 m[i] = solmoves[i] * 2 + 1;
25 }
26 return (new MoveSequence(sollen, m, solamount));
27 }
28
29 public void mix(CubePosition cubePos) {
30 int i, j;
31 // direct method, not random moves
32 cubePos.reset();
33 // first mix corners
34 // corner 5
35 j = (int) (6 * Math.random());
36 if (j == 4)
37 cubePos.doMove(3);
38 else if (j < 4) {
39 while (j > 0) {
40 cubePos.doMove(1);
41 j--;
42 }
43 cubePos.doMove(3);
44 cubePos.doMove(3);
45 }
46 // corner 4
47 j = (int) (5 * Math.random());
48 if (j < 4) {
49 while (j > 0) {
50 cubePos.doMove(1);
51 j--;
52 }
53 cubePos.doMove(3);
54 cubePos.doMove(3);
55 cubePos.doMove(3);
56 cubePos.doMove(1);
57 cubePos.doMove(3);
58 }
59 // corners 0-3
60 j = (int) (4 * Math.random());
61 while (j > 0) {
62 cubePos.doMove(1);
63 j--;
64 }
65
66 // corner orientation

Pagina 233 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverTwoGen

67 num2ori(cubePos.cubeletOri, 0, 6, 3, (int) (243 * Math.random()));


68
69 // permute edges
70 int edges[] = { 8, 9, 10, 11, 12, 13, 16 };
71 int pr[] = new int[7];
72 do {
73 num2perm(pr, 0, 7, (int) (5040 * Math.random()));
74 } while (parityOdd(pr, 0, 7) != parityOdd(cubePos.cubeletPerm, 0, 6));
75 for (i = 0; i < 7; i++) {
76 cubePos.cubeletPerm[edges[i]] = edges[pr[i]];
77 j = (i == 4 || i == 5) ? 1 : 0;
78 if (pr[i] == 4 || pr[i] == 5)
79 j = 1 - j;
80 cubePos.cubeletOri[edges[i]] = j;
81 }
82
83 // centre orientation
84 i = (int) (8 * Math.random());
85 cubePos.cubeletOri[21] = i & 3;
86 cubePos.cubeletOri[23] = ((i & 4) >> 1);
87 if (parityOdd(cubePos.cubeletPerm, 0, 6)) {
88 cubePos.cubeletOri[23] += 1 - (i & 1);
89 } else {
90 cubePos.cubeletOri[23] += (i & 1);
91 }
92 }
93
94 public boolean setPosition(CubePosition cubePos, boolean test) {
95 int i, j;
96 int block[] = { 6, 7, 14, 15, 17, 18, 19 };
97 // check 2x2x3 block
98 for (i = 0; i < 7; i++)
99 if (cubePos.cubeletOri[block[i]] != 0 || cubePos.cubeletPerm[block[i]]
100 != block[i])
101 return (false);
102
103 // check corner ori
104 j = 0;
105 for (i = 0; i < 8; i++) {
106 j += cubePos.cubeletOri[i];
107 if (j > 2)
108 j -= 3;
109 }
110 if (j != 0)
111 return (false);
112
113 // check edge ori
114 // unfortunately flip is defined wrt rl faces!
115 for (i = 8; i < 20; i++) {
116 j = cubePos.cubeletOri[i];
117 if (i >= 12 && i < 16)
118 j = 1 - j;
119 if (cubePos.cubeletPerm[i] >= 12 && cubePos.cubeletPerm[i] < 16)
120 j = 1 - j;
121 if (j != 0)
122 return (false);
123 }
124
125 // check permutation parity
126 if (parityOdd(cubePos.cubeletPerm, 0, 20))
127 return (false);
128
129 // check centre ori
130 if (cubieSettings.superGroup) {
131 if (cubePos.cubeletOri[20] != 0 || cubePos.cubeletOri[22] != 0
132 || cubePos.cubeletOri[24] != 0 || cubePos.cubeletOri[25] != 0)

Pagina 234 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverTwoGen

133 return (false);


134 if (parityOdd(cubePos.cubeletPerm, 0, 8)) {
135 if ((cubePos.cubeletOri[21] & 1) == (cubePos.cubeletOri[23] & 1))
136 return (false);
137 } else {
138 if ((cubePos.cubeletOri[21] & 1) != (cubePos.cubeletOri[23] & 1))
139 return (false);
140 }
141 }
142
143 // copy corner permutation
144 int corn[] = new int[7];
145 for (i = 0; i < 6; i++)
146 corn[i] = cubePos.cubeletPerm[i];
147 // solve corner 0
148 if (corn[1] == 0) {
149 cycle(corn, 1, 2, 3, 0);
150 } else if (corn[2] == 0) {
151 cycle(corn, 2, 1, 5, 0);
152 } else if (corn[3] == 0) {
153 cycle(corn, 3, 2, 1, 0);
154 } else if (corn[4] == 0) {
155 cycle(corn, 4, 5, 1, 0);
156 } else if (corn[5] == 0) {
157 cycle(corn, 5, 1, 2, 0);
158 }
159
160 // solve corner 1
161 if (corn[2] == 1) {
162 cycle(corn, 2, 5, 4, 1);
163 } else if (corn[3] == 1) {
164 cycle(corn, 3, 2, 5, 1);
165 } else if (corn[4] == 1) {
166 cycle(corn, 4, 5, 2, 1);
167 } else if (corn[5] == 1) {
168 cycle(corn, 5, 2, 3, 1);
169 }
170
171 // solve corner 2
172 while (corn[3] == 2 || corn[4] == 2 || corn[5] == 2) {
173 cycle(corn, 2, 3, 5, 4);
174 }
175
176 if (corn[3] != 3 || corn[4] != 4 || corn[5] != 5)
177 return (false);
178
179 if (test)
180 return (true);
181 if (!prepared)
182 return (false);
183
184 int newpos[] = { 0, 0, 0 };
185 // corner position
186 for (i = 0; i < 6; i++)
187 corn[i] = cubePos.cubeletPerm[i];
188 newpos[0] = perm2num(corn, 0, 6);
189 // edge position
190 final int edg[] = { 8, 9, 10, 11, 12, 13, 16 };
191 for (i = 0; i < 7; i++)
192 corn[i] = cubePos.cubeletPerm[edg[i]];
193 newpos[1] = perm2num(corn, 0, 7);
194 // corner orientation
195 newpos[2] = 0;
196 for (i = 4; i >= 0; i--)
197 newpos[2] = newpos[2] * 3 + cubePos.cubeletOri[i];
198 if (cubieSettings.superGroup) {

Pagina 235 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverTwoGen

199 newpos[2] = (newpos[2] << 4) + (cubePos.cubeletOri[23] << 2)


200 + cubePos.cubeletOri[21];
201 }
202
203 if (positionlist == null) {
204 positionlist = new int[40][3];
205 maxdepth = sollen = 0;
206 solmoves[0] = -1;
207 solamount[0] = 3;
208 } else if (positionlist[0][0] != newpos[0] || positionlist[0][1] != newpos[1]
209 || positionlist[0][2] != newpos[2]) {
210 // clear out search history
211 maxdepth = sollen = 0;
212 solmoves[0] = -1;
213 solamount[0] = 3;
214 }
215 // set position
216 positionlist[0][0] = newpos[0];
217 positionlist[0][1] = newpos[1];
218 positionlist[0][2] = newpos[2];
219 return (true);
220 }
221
222 // initialise tables
223 protected void init() {
224 int i, k, m, p, q;
225 transEdge = new int[5040][2];
226 transCorn = new int[720][2];
227 transOri = new int[243][2];
228 transOri2 = new int[3888][2];
229 pruneEdge = new byte[5040];
230 pruneCorn = new byte[720];
231 pruneOri = new byte[243];
232 pruneOri2 = new byte[3888];
233
234 for (i = 0; i < 5040; i++) { // each edge position
235 for (m = 0; m < 2; m++) { // each move
236 transEdge[i][m] = gettransEdge(i, m);
237 }
238 }
239 for (i = 0; i < 720; i++) { // each corner position
240 for (m = 0; m < 2; m++) { // each move
241 transCorn[i][m] = gettransCorn(i, m);
242 }
243 }
244 for (i = 0; i < 243; i++) { // each corner position
245 for (m = 0; m < 2; m++) { // each move
246 transOri[i][m] = gettransOri(i, m);
247 }
248 }
249 for (i = 0; i < 3888; i++) { // each corner position
250 for (m = 0; m < 2; m++) { // each move
251 transOri2[i][m] = gettransOri2(i, m);
252 }
253 }
254
255 // calculate pruning tables. First edges
256 int l = 1;
257 pruneEdge[0] = 1;
258 do {
259 k = 0;
260 for (i = 0; i < 5040; i++) {
261 if (pruneEdge[i] == l) {
262 for (m = 0; m < 2; m++) {
263 p = i;
264 for (q = 0; q < 3; q++) {

Pagina 236 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverTwoGen

265 p = transEdge[p][m];
266 if (pruneEdge[p] == 0) {
267 pruneEdge[p] = (byte) (l + 1);
268 k++;
269 }
270 }
271 }
272 }
273 }
274 l++;
275 } while (k != 0);
276
277 // Now corner pruning table
278 l = 1;
279 pruneCorn[0] = 1;
280 do {
281 k = 0;
282 for (i = 0; i < 720; i++) {
283 if (pruneCorn[i] == l) {
284 for (m = 0; m < 2; m++) {
285 p = i;
286 for (q = 0; q < 3; q++) {
287 p = transCorn[p][m];
288 if (pruneCorn[p] == 0) {
289 pruneCorn[p] = (byte) (l + 1);
290 k++;
291 }
292 }
293 }
294 }
295 }
296 l++;
297 } while (k != 0);
298
299 // Now corner orientation pruning table
300 l = 1;
301 pruneOri[0] = 1;
302 do {
303 k = 0;
304 for (i = 0; i < 243; i++) {
305 if (pruneOri[i] == l) {
306 for (m = 0; m < 2; m++) {
307 p = i;
308 for (q = 0; q < 3; q++) {
309 p = transOri[p][m];
310 if (pruneOri[p] == 0) {
311 pruneOri[p] = (byte) (l + 1);
312 k++;
313 }
314 }
315 }
316 }
317 }
318 l++;
319 } while (k != 0);
320 // Now corner+centre orientation pruning table
321 l = 1;
322 pruneOri2[0] = 1;
323 do {
324 k = 0;
325 for (i = 0; i < 3888; i++) {
326 if (pruneOri2[i] == l) {
327 for (m = 0; m < 2; m++) {
328 p = i;
329 for (q = 0; q < 3; q++) {
330 p = transOri2[p][m];

Pagina 237 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverTwoGen

331 if (pruneOri2[p] == 0) {
332 pruneOri2[p] = (byte) (l + 1);
333 k++;
334 }
335 }
336 }
337 }
338 }
339 l++;
340 } while (k != 0);
341 }
342
343 private int gettransEdge(int pos, int m) {
344 // convert pos number into edge permutation
345 int edges[] = new int[7];
346 num2perm(edges, 0, 7, pos);
347 // do move U,R
348 if (m == 0) {// U
349 cycle(edges, 0, 3, 2, 1);
350 } else if (m == 1) { // R
351 cycle(edges, 0, 5, 6, 4);
352 }
353 // convert back to number
354 return (perm2num(edges, 0, 7));
355 }
356
357 private int gettransCorn(int pos, int m) {
358 // convert pos number into corner permutation
359 int corn[] = new int[6];
360 num2perm(corn, 0, 6, pos);
361 // do move U,R
362 if (m == 0) {// U
363 cycle(corn, 0, 3, 2, 1);
364 } else if (m == 1) { // R
365 cycle(corn, 0, 1, 5, 4);
366 }
367 // convert back to number
368 return (perm2num(corn, 0, 6));
369 }
370
371 private int gettransOri(int pos, int m) {
372 // convert pos number into permutation
373 int corn[] = new int[6];
374 num2ori(corn, 0, 6, 3, pos);
375
376 // do move L U F R D B
377 if (m == 0) {// U
378 cycle(corn, 0, 3, 2, 1);
379 } else if (m == 1) { // R
380 cycle(corn, 0, 1, 5, 4);
381 corn[0] += 2;
382 corn[1]++;
383 corn[5] += 2;
384 corn[4]++;
385 }
386 // convert back to number
387 return (ori2num(corn, 0, 6, 3));
388 }
389
390 private int gettransOri2(int pos, int m) {
391 // convert pos number into permutation
392 int corn[] = new int[8];
393 num2ori(corn, 0, 6, 3, pos >> 4);
394 corn[6] = pos & 3;
395 corn[7] = (pos >> 2) & 3;
396

Pagina 238 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverTwoGen

397 // do move L U F R D B
398 if (m == 0) {// U
399 cycle(corn, 0, 3, 2, 1);
400 corn[6] = (corn[6] + 3) & 3;
401 } else if (m == 1) { // R
402 cycle(corn, 0, 1, 5, 4);
403 corn[0] += 2;
404 corn[1]++;
405 corn[5] += 2;
406 corn[4]++;
407 corn[7] = (corn[7] + 3) & 3;
408 }
409 // convert back to number
410 return ((ori2num(corn, 0, 6, 3) << 4) + (corn[7] << 2) + corn[6]);
411 }
412
413 // solve a position
414 protected boolean solve() {
415 // do IDA* - search depth first for each maxdepth.
416 while (!search()) {
417 if (wanttostop)
418 return (false);
419 maxdepth++;
420 }
421 return (true);
422 }
423
424 private boolean search() {
425 // do a depth search through all positions at depth maxdepth.
426 // return false if no solution, or break out with true if solved.
427 int m, nxt;
428
429 // do check for solved position with null solution.
430 if (maxdepth == 0 && sollen == 0 && positionlist[0][0] == 0 && positionlist[0][1] == 0
431 && positionlist[0][2] == 0)
432 return (true);
433
434 while (sollen >= 0) {
435 // at this point positionlist[0..sollen] are visited positions
436 // and solmoves[0..sollen-1] are moves performed.
437 // Note solmoves[sollen] is last tried (rejected) next move
438 nxt = sollen + 1;
439 // add extra half turn to last move
440 m = solmoves[sollen];
441 if (m >= 0) { // ignore dummy -1 move
442 positionlist[nxt][0] = transCorn[positionlist[nxt][0]][m];
443 positionlist[nxt][1] = transEdge[positionlist[nxt][1]][m];
444 if (cubieSettings.superGroup) {
445 positionlist[nxt][2] = transOri2[positionlist[nxt][2]][m];
446 } else {
447 positionlist[nxt][2] = transOri[positionlist[nxt][2]][m];
448 }
449 } else {
450 positionlist[nxt][0] = positionlist[sollen][0];
451 positionlist[nxt][1] = positionlist[sollen][1];
452 positionlist[nxt][2] = positionlist[sollen][2];
453 }
454 solamount[sollen]++;
455 // if done full turn, then move to next face
456 if (solamount[sollen] > 3) {
457 // next face, 0 turns yet
458 solamount[sollen] = 0;
459 do {
460 solmoves[sollen]++;
461 } while (sollen != 0 && solmoves[sollen] == solmoves[sollen - 1]);
462 if (solmoves[sollen] >= 2) {

Pagina 239 van 329 CubeThesis™ Depamelaere-Deschuytter


class SolverTwoGen

463 // done all faces. backtrack


464 sollen--;
465 continue;
466 }
467 continue; // loop back to do a quarter turn of this new face
468 }
469
470 // check pruning for proposed new position
471 if (sollen + pruneCorn[positionlist[nxt][0]] < maxdepth + 1
472 && sollen + pruneEdge[positionlist[nxt][1]] < maxdepth + 1
473 && (cubieSettings.superGroup
474 || sollen + pruneOri[positionlist[nxt][2]] < maxdepth + 1)
475 && (!cubieSettings.superGroup
476 || sollen + pruneOri2[positionlist[nxt][2]] < maxdepth + 1)) {
477 // its ok, officially add to movelist
478 // append dummy move to list for later extension.
479 solmoves[nxt] = -1;
480 solamount[nxt] = 3;
481 sollen = nxt;
482 // check if have found solution of required length;
483 if (sollen >= maxdepth)
484 return (true);
485 }
486
487 if (wanttostop)
488 return (false);
489 // loop back to shift to next move sequence
490 }
491 // reset for next search
492 solmoves[0] = -1;
493 solamount[0] = 3;
494 sollen = 0;
495 return (false);
496 }
497 }

Pagina 240 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

1 // Rubik's Cube simulator


2 //Source http://www.jaapsch.net/puzzles/cubie.htm
3 package solver.solverJS.viewSolverJS;
4
5 import java.awt.*;
6 import java.awt.event.*;
7
8 import javax.swing.*;
9
10 import solver.solverJS.algorithm.*;
11 import model.CBTHSettingsList;
12
13 public final class Cubie extends JPanel
14 implements ActionListener, ItemListener, FocusListener, Runnable {
15
16 private static final long serialVersionUID = 113215651321L;
17 final int NUMGROUPS = 5;
18 final int NUMVIEWS = 4;
19 final int VIEWWIDTH = 300; // originally 300
20 final int VIEWHEIGHT = 275; // originally 350
21
22 private CubieSettings cubieSettings = new CubieSettings();
23 int symType = 0;
24 int viewer = 0;
25 Viewer cubeViewers[] = { new Viewer3D(VIEWWIDTH, VIEWHEIGHT, cubieSettings, this),
26 new ViewerDiag(VIEWWIDTH, VIEWHEIGHT, cubieSettings, this),
27 new ViewerBox(VIEWWIDTH, VIEWHEIGHT, cubieSettings, this),
28 new ViewerFlat(VIEWWIDTH, VIEWHEIGHT, cubieSettings, this) };
29
30 private CBTHSettingsList cbthsl;
31
32 JPanel rightPanel;
33 JButton mixBut;
34 JButton resetBut;
35 JButton editBut;
36 JButton solveBut;
37
38 JButton viewBut;
39 JButton viewResetBut;
40
41 JPanel solPlayContr;
42 JPanel boxPanel;
43 JPanel solverPanel;
44 JButton gensolBut;
45 JTextField textBox;
46
47 // References to play-pause-stop... icons:
48 String[] iconFileName = { "Play-icon.png", "ReversePlay-icon.png",
49 "SkipForward-icon.png", "SkipBackward-icon.png", "FastForwardEnd-icon.png",
50 "FastBackwardBegin-icon.png" };
51 JButton[] playerbuttons = new JButton[6];
52
53 JButton playBut;
54 JButton revBut;
55 JButton stepBut;
56 JButton backBut;
57 JButton endBut;
58 JButton beginBut;
59
60 JTabbedPane tabSet;
61 JPanel[] tabPanel = { new JPanel(new GridLayout(0, 2)),
62 new JPanel(new GridLayout(0, 5)) };
63
64 JCheckBox groupCheckBox[];
65 JCheckBox superBox;
66

Pagina 241 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

67 JCheckBox normal;
68 JCheckBox square;
69 JCheckBox slice;
70 JCheckBox antiSlice;
71 JCheckBox twogenerator;
72
73 // CheckboxGroup cubeGroup = new CheckboxGroup();
74 ButtonGroup buttonGroup1;
75
76 JCheckBox groupRadioBox[];
77
78 Solver solvers[] = { new SolverKociemba(this), new SolverSquare(this),
79 new SolverSlice(this), new SolverAntiSlice(this), new SolverTwoGen(this) };
80
81 JCheckBox symTwoColBox;
82 SymButton symButton[];
83 SymButton symAllImage;
84 SymButton symCurrentImage;
85 JButton symResetBut;
86
87 Color colors[] = { new Color(255, 0, 0), // unprepared
88 new Color(192, 192, 192), // prepared, ready, controls background color
89 new Color(0, 255, 0), // Running solver
90 new Color(160, 160, 160), // viewer background color
91 };
92 boolean solution = true;
93 boolean symTwoCol = false;
94 MoveSequence generator;
95 int seqPos = 0;
96 boolean playFw = true;
97 boolean moveInProgress = false;
98
99 private boolean t;
100
101 // applet control
102 boolean isPlaying = false;
103
104 public Cubie(BorderLayout bdrl, CBTHSettingsList cbthsl) {
105 super(bdrl);
106
107 this.cbthsl = cbthsl;
108
109 rightPanel = new JPanel();
110
111 mixBut = cbthsl.createJButton("Mix", "Scrambles cube at random", this);
112 mixBut.setOpaque(true);
113 mixBut.setBackground(colors[3]);
114 resetBut = cbthsl.createJButton("Reset", "Resets the cube-configuration.", this);
115 resetBut.setOpaque(true);
116 resetBut.setBackground(colors[3]);
117 editBut = cbthsl.createJButton("Edit",
118 "User can graphically edit the cube, disclaimer: changes are NOT reflected in rest of
119 CubeThesis.",
120 this);
121 editBut.setOpaque(true);
122 editBut.setBackground(colors[3]);
123 solveBut = cbthsl.createJButton("Solve",
124 "Solves the current cube-configuration with selected solver.", this);
125 solveBut.setOpaque(true);
126 solveBut.setBackground(colors[3]);
127
128 viewBut = cbthsl.createJButton("Change view",
129 "Press, to choose different cube visualization.", this);
130 viewBut.setOpaque(true);
131 viewBut.setBackground(colors[3]);
132 viewResetBut = cbthsl.createJButton("Reset view",

Pagina 242 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

133 "Resets the view angle in case 3D view was selected.", this);
134 viewResetBut.setOpaque(true);
135 viewResetBut.setBackground(colors[3]);
136
137 solPlayContr = new JPanel();
138 boxPanel = new JPanel(new BorderLayout());
139 solverPanel = new JPanel(new BorderLayout());
140 gensolBut = cbthsl.createJButton("Solution",
141 "Toggle to switch between generating or solving sequence.", this);
142 textBox = cbthsl.createJTextField("", true, null);
143 textBox.setHorizontalAlignment(JTextField.LEFT);
144
145 playBut = new JButton();
146 revBut = new JButton();
147 stepBut = new JButton();
148 backBut = new JButton();
149 endBut = new JButton();
150 beginBut = new JButton();
151
152 groupCheckBox = new JCheckBox[NUMGROUPS];
153 superBox = cbthsl.createJCheckBox("Supergroup", false, null);
154
155 normal = cbthsl.createJCheckBox("Normal - Kociemba", true, null);
156 square = cbthsl.createJCheckBox("Square", false, null);
157 slice = cbthsl.createJCheckBox("Slice", false, null);
158 antiSlice = cbthsl.createJCheckBox("Anti-Slice", false, null);
159 twogenerator = cbthsl.createJCheckBox("2-generator", false, null);
160
161 buttonGroup1 = new ButtonGroup();
162
163 symTwoColBox = cbthsl.createJCheckBox("2 col.", false,
164 "Restrict generator to only two colors per face.");
165 symButton = new SymButton[29];
166 symAllImage = new SymButton(null, 0);
167 symCurrentImage = new SymButton(null, 0);
168 symResetBut = cbthsl.createJButton("Clear", "Clears the selected symmetry.", this);
169
170 this.init();
171 }
172
173 public void init() {
174 int i;
175
176 final int vw = VIEWWIDTH, vh = VIEWHEIGHT;
177
178 // build main applet panel
179
180 setBackground(colors[3]);
181
182 for (i = 0; i < NUMVIEWS; i++) {
183 boxPanel.add(cubeViewers[i], BorderLayout.CENTER);
184 cubeViewers[i].setBounds(0, 0, vw, vh);
185 cubeViewers[i].setVisible(i == 0);
186 cubeViewers[i].setBackground(colors[3]);
187 cubeViewers[i].setOpaque(false);
188 }
189
190 boxPanel.setPreferredSize(new Dimension(VIEWWIDTH, VIEWHEIGHT));
191
192 this.solPlayContr.setLayout(new GridLayout(1, 6));
193
194 // build right panel
195 rightPanel.setLayout(new BorderLayout());
196 rightPanel.setBackground(colors[3]);
197 rightPanel.setOpaque(true);
198

Pagina 243 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

199 JPanel fourButtonsAbove = new JPanel();


200 fourButtonsAbove.setLayout(new GridLayout(0, 4));
201 fourButtonsAbove.add(mixBut);
202 fourButtonsAbove.add(resetBut);
203 fourButtonsAbove.add(editBut);
204 fourButtonsAbove.add(solveBut);
205 fourButtonsAbove.setBackground(colors[3]);
206 fourButtonsAbove.setOpaque(true);
207 rightPanel.add(fourButtonsAbove, BorderLayout.PAGE_START);
208
209 // Build set of tabpanels
210 tabSet = new JTabbedPane();
211 tabSet.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
212 tabSet.setBackground(colors[3]);
213 tabSet.addTab("Groups", null, tabPanel[0], null);
214 tabSet.addTab("Symmetries", null, tabPanel[1], null);
215 tabSet.setFont(cbthsl.getFont("guiFont1"));
216 for (i = 0; i < 2; i++) {
217 tabPanel[i].setBackground(colors[1]);
218 tabPanel[i].setOpaque(true);
219 }
220
221 // Build group tab panel
222 groupRadioBox = new JCheckBox[] { normal, square, slice, antiSlice, twogenerator };
223
224 for (int z = 0; z < groupRadioBox.length; z++) {
225 buttonGroup1.add(groupRadioBox[z]);
226 }
227
228 for (i = 0; i < NUMGROUPS; i++) {
229 groupCheckBox[i] = new JCheckBox();
230 groupCheckBox[i].setSelected(true);
231 groupCheckBox[i].setEnabled(false);
232 groupRadioBox[i].addItemListener(this);
233 tabPanel[0].add(groupRadioBox[i]);
234 tabPanel[0].add(groupCheckBox[i]);
235
236 groupRadioBox[i].setBackground(colors[0]);
237 groupCheckBox[i].setBackground(colors[0]);
238 }
239 tabPanel[0].add(superBox);
240 superBox.setBackground(colors[1]);
241 // add all further group tab listeners
242 superBox.addItemListener(this);
243
244 // build symmetries tab panel
245 JLabel l = cbthsl.createJLabel("Current:", 1);
246 tabPanel[1].add(l);
247 symCurrentImage.setEnabled(false);
248 tabPanel[1].add(symCurrentImage);
249
250 l = cbthsl.createJLabel("Selected:", 1);
251 tabPanel[1].add(l);
252 symAllImage.setEnabled(false);
253 tabPanel[1].add(symAllImage);
254
255 tabPanel[1].add(symTwoColBox);
256
257 for (i = 0; i < 29; i++) {
258 symButton[i] = new SymButton(this, 1 << i);
259 tabPanel[1].add(symButton[i]);
260 symButton[i].setBackground(new Color(208, 208, 208));
261 }
262
263 tabPanel[1].add(symResetBut);
264 symResetBut.setBackground(new Color(208, 208, 208));

Pagina 244 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

265 // add all symmetries tab listeners


266 symTwoColBox.addItemListener(this);
267
268 // build solution box panel
269 playerbuttons[0] = playBut;
270 playerbuttons[1] = revBut;
271 playerbuttons[2] = stepBut;
272 playerbuttons[3] = backBut;
273 playerbuttons[4] = endBut;
274 playerbuttons[5] = beginBut;
275
276 String[] iconPathComp = { "img", "icon", "" };
277 for (int t = 0; t < playerbuttons.length; t++) {
278 iconPathComp[2] = iconFileName[t];
279 playerbuttons[t]
280 .setIcon(new ImageIcon(cbthsl.makeSysIndepFilePath(iconPathComp, 2)));
281 }
282
283 rightPanel.add(tabSet, BorderLayout.CENTER);
284 JPanel tussenPanel = new JPanel();
285 tussenPanel.setLayout(new GridLayout());
286 tussenPanel.add(viewBut);
287 tussenPanel.add(viewResetBut);
288 tussenPanel.setBackground(colors[3]);
289 rightPanel.add(tussenPanel, BorderLayout.PAGE_END);
290
291 solverPanel.setLayout(new BorderLayout());
292 solverPanel.add(gensolBut, BorderLayout.LINE_START);
293 solverPanel.add(textBox, BorderLayout.CENTER);
294
295 solPlayContr.add(beginBut);
296 solPlayContr.add(backBut);
297 solPlayContr.add(revBut);
298 solPlayContr.add(playBut);
299 solPlayContr.add(stepBut);
300 solPlayContr.add(endBut);
301
302 boxPanel.setBackground(colors[3]);
303 solverPanel.add(solPlayContr, BorderLayout.PAGE_END);
304
305 JLabel author = new JLabel(
306 "CUBE SOLVER: door Jaap Scherphuis © 2003-2004.
307 [http://www.jaapsch.net/puzzles/cubie.htm]");
308 author.setFont(new Font("Century Gothic", Font.BOLD, 12));
309 this.add(author, BorderLayout.PAGE_START);
310 this.add(boxPanel, BorderLayout.LINE_START);
311 this.add(rightPanel, BorderLayout.LINE_END);
312 this.add(solverPanel, BorderLayout.PAGE_END);
313
314 // add all solution box panel listeners
315 // gensolBut.addActionListener(this);
316 textBox.addActionListener(this);
317 textBox.addFocusListener(this);
318 beginBut.addActionListener(this);
319 backBut.addActionListener(this);
320 revBut.addActionListener(this);
321 playBut.addActionListener(this);
322 stepBut.addActionListener(this);
323 endBut.addActionListener(this);
324
325 // initialise all solvers
326 for (i = 0; i < NUMGROUPS; i++) {
327 solvers[i].setSettings(cubieSettings);
328 new Thread(solvers[i]).start();
329 }
330 cubeViewers[viewer].repaint();

Pagina 245 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

331 updateStatus(false);
332
333 }
334
335 public void stop() {
336 // tell thread to stop
337 if (isPlaying) {
338 isPlaying = false;
339 while (moveInProgress) {
340 try {
341 Thread.sleep(50);
342 } catch (Exception ignored) {
343 }
344 }
345 cubieSettings.lockViewer = false;
346 }
347 }
348
349 public void run() {
350 int f, q;
351 isPlaying = true;
352 cubieSettings.lockViewer = true;
353 do {
354 if (playFw) {
355 f = generator.getMoves()[seqPos];
356 q = generator.getAmount()[seqPos];
357 if (cubeViewers[viewer].showMove(f, q)) {
358 moveInProgress = (viewer == 0);
359 seqPos++;
360 }
361 if (seqPos >= generator.getLength())
362 isPlaying = false;
363 } else {
364 seqPos--;
365 f = generator.getMoves()[seqPos];
366 q = generator.getAmount()[seqPos];
367 if (!cubeViewers[viewer].showMove(f, 4 - q)) {
368 seqPos++;
369 } else {
370 moveInProgress = (viewer == 0);
371 }
372 if (seqPos <= 0)
373 isPlaying = false;
374 }
375
376 textBox.setText(generator.toString(solution, seqPos));
377 if (isPlaying) {
378 try {
379 Thread.sleep(500);
380 } catch (Exception ignored) {
381 }
382 do {
383 try {
384 Thread.sleep(50);
385 } catch (Exception ignored) {
386 }
387 } while (moveInProgress);
388 }
389 } while (isPlaying);
390 cubieSettings.lockViewer = false;
391 }
392
393 private void updateStatus(boolean changed) {
394 // Update status of current tab and solver buttons
395 if (tabSet.getSelectedIndex() == 0) {
396 boolean currentSolvable = false;

Pagina 246 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

397 for (int i = 0; i < NUMGROUPS; i++) {


398 if (changed) {
399 t = solvers[i].setPosition(cubieSettings.cubePos, true);
400 groupCheckBox[i].setSelected(t);
401 } else {
402 t = groupCheckBox[i].isSelected();
403 }
404 if (i == cubieSettings.group)
405 currentSolvable = t;
406 int c = 1;
407 if (!solvers[i].isPrepared())
408 c = 0;
409 else if (solvers[i].isRunning())
410 c = 2;
411 groupCheckBox[i].setBackground(colors[c]);
412 this.groupRadioBox[i].setBackground(colors[c]);
413 }
414 t = solvers[cubieSettings.group].isPrepared() && currentSolvable;
415 } else {
416 if (changed) {
417 t = solvers[0].setPosition(cubieSettings.cubePos, true);
418 } else {
419 t = groupCheckBox[0].isSelected();
420 }
421 t = solvers[0].isPrepared() && t;
422 symCurrentImage.setType(cubieSettings.cubePos.getSym());
423 }
424 solveBut.setText(cubieSettings.solving ? "Stop" : "Solve");
425
426 solveBut.setEnabled(t || cubieSettings.solving);
427 }
428
429 public void destroy() {
430 stop();
431 if (cubieSettings.solving) {
432 // tell solver to stop
433 solvers[cubieSettings.group].stopSolving();
434 // wait till it has indeed stopped
435 while (cubieSettings.solving) {
436 try {
437 Thread.sleep(100);
438 } catch (Exception ignored) {
439 }
440 }
441 ;
442 }
443 for (int i = 0; i < NUMVIEWS; i++) {
444 remove(cubeViewers[i]);
445 }
446 remove(rightPanel);
447 remove(boxPanel);
448 }
449
450 // --- button action/listening routines ---
451 public void solve() {
452 int g = (tabSet.getSelectedIndex() == 0) ? cubieSettings.group : 0;
453 // 0 is the most common solver. [SolverKociemba]
454 if (cubieSettings.solving) {
455 for (int i = 0; i < NUMGROUPS; i++) {
456 solvers[i].stopSolving();
457 }
458 } else if (solvers[g].setPosition(cubieSettings.cubePos, false)) {
459 startSolving();
460 new Thread(solvers[g]).start();
461 }
462 }

Pagina 247 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

463
464 public void actionPerformed(ActionEvent e) {
465 int i;
466 Object src = e.getSource();
467 if (src == mixBut) {
468 if (!cubieSettings.solving) {
469 stop();// stop any animation
470 if (tabSet.getSelectedIndex() == 0) {
471 // Mixing can happen, based on what the selected solver can solve:
472 solvers[cubieSettings.group].mix(cubieSettings.cubePos);
473 } else {
474 // Mixing a cubestate can also be restricted by symmetry-condiditons,
475 // on tabpanel [Symmetry].
476 cubieSettings.cubePos.mix(symType, cubieSettings.superGroup, symTwoCol);
477 }
478 setSequencePosition(-1);
479 updateStatus(true);
480 cubeViewers[viewer].repaint();
481 }
482 } else if (src == resetBut) {
483 if (!cubieSettings.solving) {
484 stop();// stop any animation
485 cubieSettings.cubePos.reset();
486 setSequencePosition(-1);
487 updateStatus(true);
488 cubeViewers[viewer].repaint();
489 }
490 } else if (src == solveBut) {
491 stop();// stop any animation
492 solve();
493 } else if (src == gensolBut) {
494 solution = !solution;
495 gensolBut.setText(solution ? "Solution" : "Generator");
496 if (generator == null) {
497 textBox.setText("");
498 } else {
499 textBox.setText(generator.toString(solution, seqPos));
500 }
501 } else if (src == viewBut) {
502 viewer++;
503 if (viewer >= NUMVIEWS)
504 viewer = 0;
505 for (i = 0; i < NUMVIEWS; i++) {
506 cubeViewers[i].setVisible(i == viewer);
507 }
508 } else if (src == viewResetBut) {
509 cubieSettings.cubePos.resetView();
510 for (i = 0; i < NUMVIEWS; i++) {
511 cubeViewers[i].reset();
512 }
513 updateStatus(false);
514 } else if (src == editBut) {
515 cubieSettings.edit = !cubieSettings.edit;
516 editBut.setText(cubieSettings.edit ? "Play" : "Edit");
517 seqPos = -1;
518 } else if (src == textBox) {
519 // change focus, forcing focus event to be processed
520 groupRadioBox[cubieSettings.group].requestFocus();
521 } else if (src == beginBut) {
522 viewerBackToBegin();
523 } else if (src == backBut) {
524 if (solution)
525 stepForward();
526 else
527 stepBackward();
528 } else if (src == revBut) {

Pagina 248 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

529 if (solution)
530 playForward();
531 else
532 playBackward();
533 } else if (src == playBut) {
534 if (solution)
535 playBackward();
536 else
537 playForward();
538 } else if (src == stepBut) {
539 if (solution)
540 stepBackward();
541 else
542 stepForward();
543 } else if (src == endBut) {
544 stop();
545 setSequencePosition((generator == null || solution)
546 ? 0 : generator.getLength());
547 cubeViewers[viewer].repaint();
548 } else if (src == symResetBut) {
549 // reset all buttons
550 for (i = 0; i < 29; i++)
551 symButton[i].setPressed(false);
552 symType = 0;
553 symAllImage.setType(symType);
554 } else if (src == tabSet) {
555 updateStatus(true);
556 } else {
557 // check for viewer actions
558 for (i = 0; i < NUMVIEWS; i++) {
559 if (src == cubeViewers[i]) {
560 updateStatus(true);
561 if (e.getActionCommand() == "user") {
562 seqPos = -1;
563 if (generator != null)
564 textBox.setText(generator.toString(solution, seqPos));
565 } else {
566 moveInProgress = false;
567 }
568 return;
569 }
570 }
571
572 /*
573 * check for solver actions: 0 = a Initialisation done 1 = b Solution
574 * found 2 = c Solver aborted by user 3 = d Solver finished, no solution
575 * found 4 = e Solver is solving
576 */
577
578 for (i = 0; i < NUMGROUPS; i++) {
579 if (src == solvers[i]) {
580 String nameSolver = solvers[i].getClass().getSimpleName();
581 switch (e.getActionCommand()) {
582 case "a":
583 /*
584 * System.out.println(Solver \""+nameSolver+"\" was initialized.");
585 */cubieSettings.lastOutputSolver = 0;
586 break;
587 case "b":
588 stoppedSolving();
589 System.out.println("Solver [" + nameSolver + "]: Solution found!");
590 generator = cubieSettings.generator;
591
592 // Line below was commented so the available solution will not be
593 // directly reset after finding it;
594 // cubieSettings.generator=null;

Pagina 249 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

595
596 seqPos = generator.getLength();
597 textBox.setText(generator.toString(solution, seqPos));
598 cubieSettings.cubePos.doSequence(generator);
599
600 cubieSettings.lastOutputSolver = 1;
601 break;
602 case "c":
603 stoppedSolving();
604 System.out.println("Solver [" + nameSolver + "]: Was cancelled.");
605 cubieSettings.lastOutputSolver = 2;
606 break; // aborted solve
607 case "d":
608 stoppedSolving();
609 System.out.println("Solver [" + nameSolver
610 + "]: Stopped abruptly. It is likely that this "
611 + "solver won't achieve any shorter solution.");
612 cubieSettings.lastOutputSolver = 3;
613 break; // ended solve
614 case "e":
615 System.out.println("Solver [" + nameSolver + "]: Started...");
616 cubieSettings.lastOutputSolver = 4;
617 break; // started solve
618 }
619
620 updateStatus(false);
621 return;
622 }
623 }
624
625 // check for symbutton actions
626 for (i = 0; i < 29; i++) {
627 if (src == symButton[i]) {
628 if (e.getActionCommand() != "") { // perform ref/rot
629 if (!cubieSettings.lockViewer) {
630 if (seqPos >= 0 && generator != null) {
631 generator.doSym(i);
632 textBox.setText(generator.toString(solution, seqPos));
633 }
634 cubieSettings.cubePos.doSym(i, e.getActionCommand() == "c");
635 updateStatus(true);
636 cubeViewers[viewer].repaint();
637 }
638 } else {
639 if (!symButton[i].isPressed()) {
640 symType |= 1 << i;
641 symButton[i].setPressed(true);
642 } else {
643 symType &= ~(1 << i);
644 symButton[i].setPressed(false);
645 }
646 symAllImage.setType(symType);
647 }
648 return;
649 }
650 }
651 }
652 }
653
654 // enable all buttons
655 void stoppedSolving() {
656 cubieSettings.lockViewer = false;
657 textBox.setEnabled(true);
658 mixBut.setEnabled(true);
659 resetBut.setEnabled(true);
660 superBox.setEnabled(true);

Pagina 250 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

661
662 playBut.setEnabled(true);
663 revBut.setEnabled(true);
664 stepBut.setEnabled(true);
665 backBut.setEnabled(true);
666 endBut.setEnabled(true);
667 beginBut.setEnabled(true);
668 }
669
670 // disable all buttons
671 void startSolving() {
672 cubieSettings.lockViewer = true;
673 textBox.setEnabled(false);
674 mixBut.setEnabled(false);
675 resetBut.setEnabled(false);
676 superBox.setEnabled(false);
677
678 playBut.setEnabled(false);
679 revBut.setEnabled(false);
680 stepBut.setEnabled(false);
681 backBut.setEnabled(false);
682 endBut.setEnabled(false);
683 beginBut.setEnabled(false);
684 }
685
686 private void stepForward() {
687 if (isPlaying) {
688 stop();
689 } else if (generator != null && seqPos < generator.getLength()) {
690 if (seqPos < 0)
691 setSequencePosition(0);
692 int f = generator.getMoves()[seqPos];
693 int q = generator.getAmount()[seqPos];
694 if (cubeViewers[viewer].showMove(f, q))
695 seqPos++;
696 textBox.setText(generator.toString(solution, seqPos));
697 }
698 }
699
700 public void stepBackward() {
701 if (isPlaying) {
702 stop();
703 } else if (generator != null) {
704 if (seqPos < 0)
705 setSequencePosition(generator.getLength());
706 if (seqPos > 0) {
707 seqPos--;
708 int f = generator.getMoves()[seqPos];
709 int q = generator.getAmount()[seqPos];
710 if (!cubeViewers[viewer].showMove(f, 4 - q))
711 seqPos++;
712 textBox.setText(generator.toString(solution, seqPos));
713 }
714 }
715 }
716
717 private void playForward() {
718 if (isPlaying) {
719 stop();
720 } else if (generator != null && seqPos < generator.getLength()) {
721 if (seqPos < 0)
722 setSequencePosition(0);
723 playFw = true;
724 new Thread(this).start();
725 }
726 }

Pagina 251 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

727
728 private void playBackward() {
729 if (isPlaying) {
730 stop();
731 } else if (generator != null) {
732 if (seqPos < 0)
733 setSequencePosition(generator.getLength());
734 if (seqPos > 0) {
735 playFw = false;
736 new Thread(this).start();
737 }
738 }
739 }
740
741 private void setSequencePosition(int p) {
742 if (generator == null) {
743 textBox.setText("");
744 seqPos = -1;
745 } else {
746 if (p > generator.getLength())
747 p = generator.getLength();
748 seqPos = p;
749 if (p >= 0)
750 cubieSettings.cubePos.doSequence(generator, p);
751 textBox.setText(generator.toString(solution, seqPos));
752 updateStatus(true);
753 }
754 }
755
756 public void itemStateChanged(ItemEvent e) {
757 int i;
758 Object src = e.getSource();
759 if (src == superBox) {
760 cubieSettings.superGroup = !cubieSettings.superGroup;
761 // now set box to reflect actual choice of group
762 superBox.setSelected(cubieSettings.superGroup);
763 // update group solvability flags
764 updateStatus(true);
765 // update view
766 cubeViewers[viewer].repaint();
767 return;
768 } else if (src == symTwoColBox) {
769 symTwoCol = !symTwoCol;
770 // set box to reflect actual choice
771 symTwoColBox.setSelected(symTwoCol);
772 return;
773 }
774 for (i = 0; i < NUMGROUPS; i++) {
775 if (src == groupRadioBox[i]) {
776 cubieSettings.group = i;
777 // now set box to reflect actual choice of group
778
779 // OPGELET: dit nog aanpassen!!
780 // cubeGroup.setSelectedCheckbox(groupRadioBox[cubieSettings.group]);
781 // update (group solvability flags and) solve button
782 updateStatus(false);
783 return;
784 }
785 }
786 }
787
788 public void focusLost(FocusEvent e) {
789 Object src = e.getSource();
790 if (src == textBox) {
791 textChanged();
792 }

Pagina 252 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

793 }
794
795 public void focusGained(FocusEvent e) {
796 }
797
798 private void textChanged() {
799 if (!cubieSettings.solving) {
800 if (generator == null)
801 generator = new MoveSequence();
802 generator.parse(textBox.getText(), solution);
803 seqPos = generator.getLength();
804 textBox.setText(generator.toString(solution, seqPos));
805 cubieSettings.cubePos.doSequence(generator);
806 updateStatus(true);
807 cubeViewers[viewer].repaint();
808 }
809 }
810
811 // Has something to do with the solvability of the represented cube.
812 public boolean getT() {
813 return t;
814 }
815
816 public CubieSettings getSettings() {
817 return cubieSettings;
818 }
819
820 public void cubieSetCube(int[] tempCubeletPerm, int[] tempCubeletOri,
821 int[] tempFaceOri) {
822
823 // Do the same as resetting:
824 if (!cubieSettings.solving) {
825 stop();// stop any animation
826 cubieSettings.cubePos.reset();
827 setSequencePosition(-1);
828 updateStatus(true);
829 cubeViewers[viewer].repaint();
830 }
831
832 cubieSettings.cubePos = new CubePosition(tempCubeletPerm, tempCubeletOri,
833 tempFaceOri);
834
835 updateStatus(true);
836 cubeViewers[viewer].repaint();
837 cubeViewers[viewer].revalidate();
838
839 }
840
841 /**
842 * [WIP] Cubie sets it solutionbar, to what he gets from the CBTHSaveFile, but
843 * it's not working yet.
844 *
845 * @param solMoves
846 * solutionMoves from the CommandSeq Class.
847 * @param solAmount
848 * solutionAmount from the CommandSeq Class.
849 * @param solLen
850 * solutionLength from the CommandSeq Class.
851 * @param robotPositionHor
852 * robots position from the CommandSeq Class.
853 */
854 public void cubieSetMoveSeq(int[] solMoves, int[] solAmount, int solLen,
855 int robotPositionHor) {
856
857 // [WIP]: This did not quite work:
858

Pagina 253 van 329 CubeThesis™ Depamelaere-Deschuytter


class Cubie

859 /*
860 * cubieSettings.generator = new MoveSequence(solLen, solMoves, solAmount);
861 * //Update visualization to robotPositionHor
862 *
863 * stop(); solution = true; seqPos = robotPositionHor; setSequencePosition(
864 * robotPositionHor); cubeViewers[viewer].repaint();
865 *
866 * updateStatus(true);
867 */
868 }
869
870 public MoveSequence getMoveSeqGenerator() {
871 return cubieSettings.generator;
872 }
873
874 public void viewerBackToBegin() {
875 stop();
876 setSequencePosition((generator != null && solution) ? generator.getLength() : 0);
877 cubeViewers[viewer].repaint();
878 }
879 }

Pagina 254 van 329 CubeThesis™ Depamelaere-Deschuytter


class SymButton

1 package solver.solverJS.viewSolverJS;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 // SymButton
8 // This is a kind button with cube symmetry picture on it.
9 // Button can remain depressed or not, depending on setPressed(boolean) state
10 // When clicked, an ActionEvent is passed to single ActionListener, with
11 // name 's' if shift key pressed during click or '' otherwise.
12 // If disabled then no longer a button, just the picture.
13
14 public final class SymButton extends JButton implements MouseListener {
15
16 private static final long serialVersionUID = 1L;
17 private Image offImage;
18 private Graphics offGraphics;
19 private ActionListener main;
20 private boolean pressed;
21 private int centx, centy, width, height;
22 private int vec[][];
23 private int type;
24 private Color colors[] = { new Color(0, 0, 0), // drawing colour
25 new Color(64, 64, 64), // shadowed edge outside
26 new Color(128, 128, 128), // shadowed edge inside
27 new Color(224, 224, 224), // highlighted edge inside
28 new Color(255, 255, 255), // highlighted edge outside
29 new Color(255, 0, 0), // m colour
30 new Color(255, 128, 128), // mc colour
31 new Color(255, 0, 255), // r2 colour
32 new Color(0, 255, 255), // r3 colour
33 new Color(0, 0, 255), // r4 colour
34 };
35
36 public SymButton(ActionListener m, int t) {
37 main = m;
38 pressed = false;
39 type = t;
40 addMouseListener(this);
41 }
42
43 public boolean isPressed() {
44 return (pressed);
45 }
46
47 public void setPressed(boolean p) {
48 pressed = p;
49 repaint();
50 }
51
52 void setType(int t) {
53 type = checkSym(t);
54 repaint();
55 }
56
57 void initialise() {
58 width = getSize().width;
59 height = getSize().height;
60
61 offImage = createImage(width, height); // Double buffer
62 offGraphics = offImage.getGraphics();
63
64 centx = (width - 1) / 2;
65 centy = (height - 1) / 2;
66 int rad = (int) ((centx - 1) / .866);

Pagina 255 van 329 CubeThesis™ Depamelaere-Deschuytter


class SymButton

67 if (rad > centy - 1)


68 rad = centy - 1;
69
70 vec = new int[][] { { 0, rad }, { (int) (-rad * .866), -rad / 2 },
71 { (int) (rad * .866), -rad / 2 }, { 0, rad },
72 { (int) (-rad * .866), -rad / 2 }, { (int) (rad * .866), -rad / 2 } };
73 }
74
75 public void paint(Graphics g) {
76 int i;
77 if (offImage == null) {
78 initialise();
79 }
80
81 if (this.isEnabled()) {
82 // draw button
83 // top left edges
84 offGraphics.setColor(colors[pressed ? 1 : 4]);
85 offGraphics.fillRect(0, 0, width, height);
86 // bot right edges
87 offGraphics.setColor(colors[pressed ? 4 : 1]);
88 offGraphics.fillRect(1, 1, width - 1, height - 1);
89 // top left edges
90 offGraphics.setColor(colors[pressed ? 2 : 3]);
91 offGraphics.fillRect(1, 1, width - 2, height - 2);
92 // bot right edges
93 offGraphics.setColor(colors[pressed ? 3 : 2]);
94 offGraphics.fillRect(2, 2, width - 3, height - 3);
95 // background
96 offGraphics.setColor(getBackground());
97 offGraphics.fillRect(2, 2, width - 4, height - 4);
98 } else {
99 // background
100 offGraphics.setColor(getBackground());
101 offGraphics.fillRect(0, 0, width, height);
102 }
103
104 int m = 1;
105
106 // centre symmetry
107 if ((type & m) != 0) {
108 offGraphics.setColor(colors[6]);
109 int r = vec[0][1] / 3;
110 offGraphics.fillOval(centx - r, centy - r, r + r, r + r);
111 }
112 m <<= 1;
113
114 // me symmetries
115 for (i = 0; i < 3; i++) {
116 if ((type & m) != 0) {
117 offGraphics.setColor(colors[5]);
118 offGraphics.drawPolyline(
119 new int[] { centx + vec[i + 1][0] + vec[i + 2][0], centx,
120 centx + vec[i][0] },
121 new int[] { centy + vec[i + 1][1] + vec[i + 2][1], centy,
122 centy + vec[i][1] },
123 3);
124 }
125 m <<= 1;
126 }
127
128 // me symmetries
129 for (i = 0; i < 3; i++) {
130 if ((type & m) != 0) {
131 offGraphics.setColor(colors[5]);
132 offGraphics.drawPolyline(

Pagina 256 van 329 CubeThesis™ Depamelaere-Deschuytter


class SymButton

133 new int[] { centx + vec[i][0] + vec[i + 1][0],


134 centx + vec[i + 1][0], centx + vec[i + 2][0],
135 centx + vec[i + 2][0] + vec[i][0] },
136 new int[] { centy + vec[i][1] + vec[i + 1][1],
137 centy + vec[i + 1][1], centy + vec[i + 2][1],
138 centy + vec[i + 2][1] + vec[i][1] },
139 4);
140 }
141 m <<= 1;
142 }
143
144 // mf symmetries
145 for (i = 0; i < 3; i++) {
146 if ((type & m) != 0) {
147 offGraphics.setColor(colors[5]);
148 offGraphics.drawPolyline(
149 new int[] { centx + vec[i + 1][0] + vec[i][0] / 2,
150 centx + vec[i][0] / 2, centx + vec[i + 2][0] + vec[i][0] / 2 },
151 new int[] { centy + vec[i + 1][1] + vec[i][1] / 2,
152 centy + vec[i][1] / 2, centy + vec[i + 2][1] + vec[i][1] / 2 },
153 3);
154 }
155 m <<= 1;
156 }
157
158 // r2f symmetries
159 m <<= 3; // display before doing m4
160 for (i = 0; i < 3; i++) {
161 if ((type & m) != 0) {
162 offGraphics.setColor(colors[7]);
163 offGraphics.fillPolygon(
164 new int[] { centx + (4 * vec[i + 1][0] + 4 * vec[i + 2][0] + 3) / 6,
165 centx + (4 * vec[i + 1][0] + 2 * vec[i + 2][0] + 3) / 6,
166 centx + (2 * vec[i + 1][0] + 2 * vec[i + 2][0] + 3) / 6,
167 centx + (2 * vec[i + 1][0] + 4 * vec[i + 2][0] + 3) / 6 },
168 new int[] { centy + (4 * vec[i + 1][1] + 4 * vec[i + 2][1] + 3) / 6,
169 centy + (4 * vec[i + 1][1] + 2 * vec[i + 2][1] + 3) / 6,
170 centy + (2 * vec[i + 1][1] + 2 * vec[i + 2][1] + 3) / 6,
171 centy + (2 * vec[i + 1][1] + 4 * vec[i + 2][1] + 3) / 6 },
172 4);
173 }
174 m <<= 1;
175 }
176 m >>= 6;
177
178 // m4 symmetries
179 for (i = 0; i < 3; i++) {
180 if ((type & m) != 0) {
181 offGraphics.setColor(colors[5]);
182 offGraphics.fillPolygon(
183 new int[] { centx + (4 * vec[i + 1][0] + 4 * vec[i + 2][0] + 3) / 6,
184 centx + (4 * vec[i + 1][0] + 2 * vec[i + 2][0] + 3) / 6,
185 centx + (2 * vec[i + 1][0] + 2 * vec[i + 2][0] + 3) / 6,
186 centx + (2 * vec[i + 1][0] + 4 * vec[i + 2][0] + 3) / 6 },
187 new int[] { centy + (4 * vec[i + 1][1] + 4 * vec[i + 2][1] + 3) / 6,
188 centy + (4 * vec[i + 1][1] + 2 * vec[i + 2][1] + 3) / 6,
189 centy + (2 * vec[i + 1][1] + 2 * vec[i + 2][1] + 3) / 6,
190 centy + (2 * vec[i + 1][1] + 4 * vec[i + 2][1] + 3) / 6 },
191 4);
192 }
193 m <<= 1;
194 }
195 m <<= 3;
196
197 // r4 symmetries
198 for (i = 0; i < 3; i++) {

Pagina 257 van 329 CubeThesis™ Depamelaere-Deschuytter


class SymButton

199 if ((type & m) != 0) {


200 offGraphics.setColor(colors[9]);
201 offGraphics.fillPolygon(
202 new int[] { centx + (4 * vec[i + 1][0] + 4 * vec[i + 2][0] + 3) / 6,
203 centx + (4 * vec[i + 1][0] + 2 * vec[i + 2][0] + 3) / 6,
204 centx + (2 * vec[i + 1][0] + 2 * vec[i + 2][0] + 3) / 6,
205 centx + (2 * vec[i + 1][0] + 4 * vec[i + 2][0] + 3) / 6 },
206 new int[] { centy + (4 * vec[i + 1][1] + 4 * vec[i + 2][1] + 3) / 6,
207 centy + (4 * vec[i + 1][1] + 2 * vec[i + 2][1] + 3) / 6,
208 centy + (2 * vec[i + 1][1] + 2 * vec[i + 2][1] + 3) / 6,
209 centy + (2 * vec[i + 1][1] + 4 * vec[i + 2][1] + 3) / 6 },
210 4);
211 }
212 m <<= 1;
213 }
214
215 // r3 symmetries
216 for (i = 0; i < 3; i++) {
217 if ((type & m) != 0) {
218 offGraphics.setColor(colors[8]);
219 offGraphics.fillPolygon(
220 new int[] { centx + vec[i][0],
221 centx + vec[i][0] + (vec[i + 1][0] + 1) / 3,
222 centx + 2 * vec[i][0] / 3,
223 centx + vec[i][0] + (vec[i + 2][0] + 1) / 3 },
224 new int[] { centy + vec[i][1],
225 centy + vec[i][1] + (vec[i + 1][1] + 1) / 3,
226 centy + 2 * vec[i][1] / 3,
227 centy + vec[i][1] + (vec[i + 2][1] + 1) / 3 },
228 4);
229 offGraphics.fillPolygon(
230 new int[] { centx + vec[i + 1][0] + vec[i + 2][0],
231 centx + (2 * vec[i + 1][0] + 3 * vec[i + 2][0]) / 3,
232 centx + (3 * vec[i + 1][0] + 2 * vec[i + 2][0]) / 3, },
233 new int[] { centy + vec[i + 1][1] + vec[i + 2][1],
234 centy + (2 * vec[i + 1][1] + 3 * vec[i + 2][1]) / 3,
235 centy + (3 * vec[i + 1][1] + 2 * vec[i + 2][1]) / 3, },
236 3);
237 }
238 m <<= 1;
239 }
240
241 if ((type & m) != 0) {
242 offGraphics.setColor(colors[8]);
243 offGraphics.fillPolygon(
244 new int[] { centx + (vec[i][0] + 1) / 3,
245 centx + (vec[i + 1][0] + 1) / 3,
246 centx + (vec[i + 2][0] + 1) / 3, },
247 new int[] { centy + (vec[i][1] + 1) / 3,
248 centy + (vec[i + 1][1] + 1) / 3,
249 centy + (vec[i + 2][1] + 1) / 3, },
250 3);
251 }
252 m <<= 1;
253
254 // cube itself
255 offGraphics.setColor(colors[0]);
256 for (i = 0; i < 3; i++) {
257 offGraphics.drawLine(centx, centy, centx + vec[i][0], centy + vec[i][1]);
258 offGraphics.drawLine(centx + vec[i][0], centy + vec[i][1],
259 centx + vec[i][0] + vec[i + 1][0], centy + vec[i][1] + vec[i + 1][1]);
260 offGraphics.drawLine(centx + vec[i][0] + vec[i + 1][0],
261 centy + vec[i][1] + vec[i + 1][1], centx + vec[i + 1][0],
262 centy + vec[i + 1][1]);
263
264 offGraphics.drawPolyline(

Pagina 258 van 329 CubeThesis™ Depamelaere-Deschuytter


class SymButton

265 new int[] { centx, centx + vec[i][0],


266 centx + vec[i][0] + vec[i + 1][0], centx + vec[i + 1][0] },
267 new int[] { centy, centy + vec[i][1],
268 centy + vec[i][1] + vec[i + 1][1], centy + vec[i + 1][1] },
269 4);
270 }
271
272 // r2e symmetries
273 for (i = 0; i < 3; i++) {
274 if ((type & m) != 0) {
275 offGraphics.setColor(colors[7]);
276 offGraphics.drawLine(centx + vec[i][0] / 3, centy + vec[i][1] / 3,
277 centx + 2 * vec[i][0] / 3, centy + 2 * vec[i][1] / 3);
278 }
279 m <<= 1;
280 }
281
282 // r2e symmetries
283 for (i = 0; i < 3; i++) {
284 if ((type & m) != 0) {
285 offGraphics.setColor(colors[7]);
286 offGraphics.drawLine(centx + vec[i + 1][0] + vec[i][0] / 3,
287 centy + vec[i + 1][1] + vec[i][1] / 3,
288 centx + vec[i + 1][0] + 2 * vec[i][0] / 3,
289 centy + vec[i + 1][1] + 2 * vec[i][1] / 3);
290 offGraphics.drawLine(centx + vec[i + 2][0] + vec[i][0] / 3,
291 centy + vec[i + 2][1] + vec[i][1] / 3,
292 centx + vec[i + 2][0] + 2 * vec[i][0] / 3,
293 centy + vec[i + 2][1] + 2 * vec[i][1] / 3);
294 }
295 m <<= 1;
296 }
297
298 // display result
299 g.drawImage(offImage, 0, 0, this);
300 }
301
302 int checkSym(int t) {
303 // add all deduced symmetries to bitmask t
304 // list of all possible subgroups of Symm_cube,
305 // from small to large
306 final int s[] = {
307 // order 2
308 0x00000001, // m_c
309 0x00000002, 0x00000004, 0x00000008, // m_e
310 0x00000010, 0x00000020, 0x00000040,
311 0x00000080, 0x00000100, 0x00000200,// m_f
312 0x00002000, 0x00004000, 0x00008000, // r2_f
313 0x00800000, 0x01000000, 0x02000000, // r2_e
314 0x04000000, 0x08000000, 0x10000000,
315 // order 3
316 0x00080000, 0x00100000, 0x00200000, 0x00400000, // r3
317 // order 4
318 0x00002400, 0x00004800, 0x00009000, // m4
319 0x00012000, 0x00024000, 0x00048000, // r4
320 0x0000E000, // r2f r2f
321 0x04802000, 0x09004000, 0x12008000, // r2e r2e
322 0x00800082, 0x01000104, 0x02000208, // mf r2e
323 0x04000090, 0x08000120, 0x10000240, 0x04000003,
324 0x08000005, 0x10000009,// me
325 // r2e
326 0x00800011, 0x01000021, 0x02000041,
327 0x00002081, 0x00004101, 0x00008201, // mc
328 // r2f
329 0x00002012, 0x00004024, 0x00008048, // me r2f
330 0x00002300, 0x00004280, 0x00008180, // mf r2f

Pagina 259 van 329 CubeThesis™ Depamelaere-Deschuytter


class SymButton

331 // order 6
332 0x07080000, 0x0A900000, 0x11A00000, 0x1C400000, // r3r2
333 0x00080001, 0x00100001, 0x00200001, 0x00400001, // mc r3
334 0x00080062, 0x00100054, 0x00200038, 0x0040000E, // me r3
335 // order 8
336 0x0481E000, 0x0902E000, 0x1204E000, // r4r2
337 0x04802093, 0x09004125, 0x12008249, // mc r2e r2e
338 0x04802700, 0x09004A80, 0x12009180, // mf r2e r2e
339 0x0000E381, // mf r2f r2f
340 0x0000E412, 0x0000E824, 0x0000F048, // me r2f r2f
341 0x00012481, 0x00024901, 0x00049201, // mc r4
342 0x00012312, 0x000242A4, 0x000481C8, // me r4
343 // order 12
344 0x0078E000, // r3r2r2
345 0x07080063, 0x0A900055, 0x11A00039, 0x1C40000F, // mr3r2
346 // order 16
347 0x0481E793, 0x0902EBA5, 0x1204F3C9, // mr4r2
348 // order 24
349 0x1FFFE000, // r4r3r2
350 0x0078E381, // mfr3r2r2
351 0x0078FC7E, // mer3r2r2
352 // order 48
353 0x1FFFFFFF,// mr4r3r2
354 };
355
356 if (t == 0)
357 return 0;
358 int i = 0;
359 while ((t & s[i]) != t)
360 i++;
361 return s[i];
362 }
363
364 public void update(Graphics g) {
365 paint(g);
366 }
367
368 public void mouseClicked(MouseEvent e) {
369 }
370
371 public void mouseEntered(MouseEvent e) {
372 }
373
374 public void mouseExited(MouseEvent e) {
375 }
376
377 public void mouseReleased(MouseEvent e) {
378 }
379
380 public void mousePressed(MouseEvent e) {
381 boolean shift = e.isShiftDown() || e.isAltDown();
382 boolean ctrl = e.isControlDown();
383 repaint();
384 e.consume();
385
386 // Pass on an event to main applet, to signify change
387 if (main != null) {
388 ActionEvent ae = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
389 shift ? "s" : ctrl ? "c" : "");
390 main.actionPerformed(ae);
391 }
392 }
393 }

Pagina 260 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer

1 // Rubik's Cube simulator


2 package solver.solverJS.viewSolverJS;
3
4 import java.awt.*;
5 import javax.swing.*;
6 import java.awt.event.*;
7 import solver.solverJS.algorithm.*;
8
9 abstract class Viewer extends JPanel
10 implements MouseListener, MouseMotionListener {
11 private static final long serialVersionUID = 1L;
12 Image offImage;
13 Graphics offGraphics;
14 int width, height;
15 Color baseColor = new Color(0, 0, 0); // black cube
16
17 // These colors are used for all viewers, instead the 3D viewer:
18 Color colors[] = { new Color(255, 0, 0), // red
19 new Color(0, 0, 255), // blue
20 new Color(255, 255, 0), // yellow
21 new Color(255, 140, 0), // orange
22 new Color(0, 255, 0), // green
23 new Color(255, 255, 255) // white
24 };
25 // cube group setting
26 CubieSettings cubieSettings;
27 ActionListener main;
28
29 public Viewer(int x, int y, CubieSettings s, ActionListener m) {
30 width = x;
31 height = y;
32 cubieSettings = s;
33 addMouseListener(this);
34 main = m;
35 }
36
37 public void initialise() {
38 offImage = createImage(width, height); // Double buffer
39 offGraphics = offImage.getGraphics();
40 }
41
42 public void reset() {
43 repaint();
44 }
45
46 // --- facelet routines ---
47 // conversion data from internal cube representation to external facelet
48 // representation
49 private void editMove(int f1, int f2) {
50 // edit mode, move facelet f1 to f2
51 // find cubelet for f1
52 int c1 = 0, o1 = 0, c2 = 0, o2 = 0;
53 boolean f = false;
54 if (cubieSettings.lockViewer)
55 return;
56 if (f1 < 0 || f2 < 0 || f1 >= 54 || f2 >= 54)
57 return;
58 for (o1 = 0; o1 < 3; o1++) {
59 for (c1 = 0; c1 < 26; c1++) {
60 if (CubePosition.cubelet2facelet[c1][o1] == f1) {
61 f = true;
62 break;
63 }
64 }
65 if (f)
66 break;

Pagina 261 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer

67 }
68 if (f == false)
69 return;
70 f = false;
71 for (o2 = 0; o2 < 3; o2++) {
72 for (c2 = 0; c2 < 26; c2++) {
73 if (CubePosition.cubelet2facelet[c2][o2] == f2) {
74 f = true;
75 break;
76 }
77 }
78 if (f)
79 break;
80 }
81 if (f == false)
82 return;
83 cubieSettings.cubePos.editMove(c1, o1, c2, o2);
84 doEvent(true);
85 repaint();
86 }
87
88 public boolean showMove(int face, int qu) {
89 cubieSettings.cubePos.doMove(face, qu, true);
90 repaint();
91 doEvent(false);
92 return (true);
93 }
94
95 // --- mouse routines ---
96 int lastX, lastY, lastF = -1;
97 int keys = 0;
98 boolean moved = false;
99 final int sensitivityDrag = 40;
100 final int sensitivityMove = 12;
101
102 public void mousePressed(MouseEvent e) {
103 addMouseMotionListener(this);
104 lastX = e.getX();
105 lastY = e.getY();
106 lastF = getFacelet(lastX, lastY);
107 keys = e.isShiftDown() ? 1 : 0;
108 keys += e.isControlDown() ? 2 : 0;
109 keys += e.isAltDown() ? 4 : 0;
110 moved = false;
111 e.consume();
112 }
113
114 public void mouseReleased(MouseEvent e) {
115 removeMouseMotionListener(this);
116 if (cubieSettings.edit && lastF >= 0) {
117 editMove(lastF, getFacelet(e.getX(), e.getY()));
118 } else if (!moved) {
119 checkMouseMove(e.getX(), e.getY(), sensitivityMove);
120 }
121 e.consume();
122 }
123
124 public void mouseDragged(MouseEvent e) {
125 if ((!cubieSettings.edit || lastF < 0) && !moved)
126 checkMouseMove(e.getX(), e.getY(), sensitivityDrag);
127 e.consume();
128 }
129
130 public void mouseMoved(MouseEvent e) {
131 }
132

Pagina 262 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer

133 public void mouseClicked(MouseEvent e) {


134 }
135
136 public void mouseEntered(MouseEvent e) {
137 }
138
139 public void mouseExited(MouseEvent e) {
140 }
141
142 abstract protected void checkMouseMove(int x, int y, int d);
143
144 abstract protected int getFacelet(int x, int y);
145
146 // m=0-5, normal turn
147 // m=6-8, middle layer turn
148 // m=9-11, cube turn
149 // m=12-14, slice move (output only)
150 // m=15-17, anti-slice move (output only)
151 // check group restrictions, parse keys, and call domove
152 // q=+/-1 or +-2.
153 public void tryMove(int m, int q) {
154
155 if (m < 9) {
156 if (cubieSettings.group == 1)
157 keys |= 1;
158 if (cubieSettings.group == 2) {
159 keys |= 2;
160 keys &= 3;
161 }
162 if (cubieSettings.group == 3) {
163 keys |= 4;
164 keys &= 5;
165 }
166 if (cubieSettings.group == 3 && m > 5)
167 keys |= 1;
168 }
169 if (cubieSettings.group == 4) {
170 if (m != 1 && m != 3 && m < 6)
171 return;
172 }
173
174 if ((keys & 1) != 0) {
175 // shift pressed: half turn
176 if (q > 0)
177 q = 2; // positive
178 else
179 q = -2;
180 }
181 if ((keys & 2) != 0 && cubieSettings.group != 4) {
182 // control pressed: Slice turn
183 if (m < 3)
184 m += 12;
185 else if (m < 6) {
186 m += 9;
187 q = -q;
188 }
189 ;
190 }
191 if ((keys & 4) != 0 && cubieSettings.group != 4) {
192 // alt pressed: Anti-slice turn
193 if (m < 3)
194 m += 15;
195 else if (m < 6)
196 m += 12;
197 }
198 doMove(m, q);

Pagina 263 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer

199 }
200
201 void doMove(int m, int q) {
202 if (cubieSettings.lockViewer)
203 return;
204 cubieSettings.cubePos.doMove(m, q, true);
205 repaint();
206 doEvent(true);
207 }
208
209 void doEvent(boolean user) {
210 // dispatch action event that move performed.
211 // two event types: usermove and automove. First is a move done
212 // by user acting on viewer via mouse. Second is move initiated from
213 // a function call from Cubie.
214 // I did not bother to implement an addActionListener method as there
215 // will only ever be one listener to this, viz the main cubie applet.
216 ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
217 user ? "user" : "auto");
218 main.actionPerformed(e);
219 }
220
221 // -- display routines ---
222 public void update(Graphics g) {
223 paint(g);
224 }
225 }

Pagina 264 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

1 package solver.solverJS.viewSolverJS;
2
3 import java.awt.*;
4 import java.awt.event.*;
5
6 import solver.solverJS.algorithm.*;
7
8 final class Viewer3D extends Viewer implements Runnable {
9 // --- Display routines ---
10
11 private static final long serialVersionUID = 1L;
12 // graphical representation data
13 int OFFSETX, OFFSETY;
14 int radius;
15 Color fgColor[][] = new Color[8][20];
16 // coordinate system wrt users view
17 float eye[][] = new float[3][3];
18 // orthogonal axes vectors
19 final float coordVec[][] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 },
20 { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, -1 }, };
21 // rotated orthogonal axes for animation
22 final int numAnimSteps = 16;
23 float animVec[][][][] = new float[6][numAnimSteps + numAnimSteps + 1][3][3];
24 // facelets (in LUFRDB order) of each cubelet. Er zijn 54 [0..53] facelets te
25 // benoemen.
26 final int facelets[][] = { { 0, 9, -1, -1, -1, 47 }, // ULB
27 { -1, 10, -1, -1, -1, 46 }, // UB
28 { -1, 11, -1, 29, -1, 45 }, // UR
29 { 1, 12, -1, -1, -1, -1 }, // UL
30 { -1, 13, -1, -1, -1, -1 }, // U
31 { -1, 14, -1, 28, -1, -1 }, // UR
32 { 2, 15, 18, -1, -1, -1 }, // ULF
33 { -1, 16, 19, -1, -1, -1 }, // UF
34 { -1, 17, 20, 27, -1, -1 }, // UFR
35
36 { 3, -1, -1, -1, -1, 50 }, { -1, -1, -1, -1, -1, 49 },
37 { -1, -1, -1, 32, -1, 48 }, { 4, -1, -1, -1, -1, -1 },
38 { -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, 31, -1, -1 },
39 { 5, -1, 21, -1, -1, -1 }, { -1, -1, 22, -1, -1, -1 },
40 { -1, -1, 23, 30, -1, -1 },
41
42 { 6, -1, -1, -1, 42, 53 }, { -1, -1, -1, -1, 43, 52 },
43 { -1, -1, -1, 35, 44, 51 }, { 7, -1, -1, -1, 39, -1 },
44 { -1, -1, -1, -1, 40, -1 }, { -1, -1, -1, 34, 41, -1 },
45 { 8, -1, 24, -1, 36, -1 }, { -1, -1, 25, -1, 37, -1 },
46 { -1, -1, 26, 33, 38, -1 } };
47 Polygon faceletsO[] = new Polygon[54];
48 float moveDirs[][] = new float[54][4];
49 boolean eventType = true;
50
51 public Viewer3D(int x, int y, CubieSettings s, ActionListener m) {
52 super(x, y, s, m);
53 int i, j;
54 OFFSETX = x / 2;
55 OFFSETY = y / 2;
56 radius = x * 3 / 16;
57 if (y < x)
58 radius = y * 3 / 16;
59 for (j = 0; j < 20; j++) {
60 i = (40 - j) * j / 20;
61 // Functie stelt bergparabool voor door oorsprong
62 // met top in (20,20)
63 //Waarschijnlijk heeft i hier
64 // iets te maken met orientatie, anders blijven de
65 // kleuren onveranderd. Van elk kleur worden er als
66 // het ware 20 schakeringen opgeslaan.

Pagina 265 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

67 fgColor[0][j] = new Color(55 + 10 * i, 0, 0); // Red


68 fgColor[1][j] = new Color(0, 0, 55 + 10 * i);// blue
69 fgColor[2][j] = new Color(55 + 10 * i, 55 + 10 * i, 0);// yellow
70 fgColor[3][j] = new Color(55 + 10 * i, 30 + 5 * i, 0);// orange
71 fgColor[4][j] = new Color(0, 55 + 10 * i, 0);// green
72 fgColor[5][j] = new Color(55 + 10 * i, 55 + 10 * i, 55 + 10 * i);// white
73 fgColor[6][j] = new Color(2 * i, 2 * i, 2 * i);
74 // Black plastic under facelets
75 fgColor[7][j] = new Color(30 + 2 * i, 30 + 2 * i, 30 + 2 * i);
76 // Color gaps between the cubelets
77 }
78
79 // calculate rotated vectors
80
81 for (i = 0; i <= numAnimSteps; i++) {
82 animVec[3][i][1][0] = 0;
83 animVec[3][i][1][1] = numAnimSteps - i;
84 animVec[3][i][1][2] = -i;
85 animVec[3][i + numAnimSteps][1][0] = 0;
86 animVec[3][i + numAnimSteps][1][1] = -i;
87 animVec[3][i + numAnimSteps][1][2] = -numAnimSteps + i;
88
89 animVec[4][i][0][0] = numAnimSteps - i;
90 animVec[4][i][0][1] = 0;
91 animVec[4][i][0][2] = i;
92 animVec[4][i + numAnimSteps][0][0] = -i;
93 animVec[4][i + numAnimSteps][0][1] = 0;
94 animVec[4][i + numAnimSteps][0][2] = numAnimSteps - i;
95
96 animVec[2][i][0][0] = numAnimSteps - i;
97 animVec[2][i][0][1] = -i;
98 animVec[2][i][0][2] = 0;
99 animVec[2][i + numAnimSteps][0][0] = -i;
100 animVec[2][i + numAnimSteps][0][1] = -numAnimSteps + i;
101 animVec[2][i + numAnimSteps][0][2] = 0;
102
103 animVec[0][i][1][0] = 0;
104 animVec[0][i][1][1] = numAnimSteps - i;
105 animVec[0][i][1][2] = i;
106 animVec[0][i + numAnimSteps][1][0] = 0;
107 animVec[0][i + numAnimSteps][1][1] = -i;
108 animVec[0][i + numAnimSteps][1][2] = numAnimSteps - i;
109
110 animVec[1][i][0][0] = numAnimSteps - i;
111 animVec[1][i][0][1] = 0;
112 animVec[1][i][0][2] = -i;
113 animVec[1][i + numAnimSteps][0][0] = -i;
114 animVec[1][i + numAnimSteps][0][1] = 0;
115 animVec[1][i + numAnimSteps][0][2] = -numAnimSteps + i;
116
117 animVec[5][i][0][0] = numAnimSteps - i;
118 animVec[5][i][0][1] = i;
119 animVec[5][i][0][2] = 0;
120 animVec[5][i + numAnimSteps][0][0] = -i;
121 animVec[5][i + numAnimSteps][0][1] = numAnimSteps - i;
122 animVec[5][i + numAnimSteps][0][2] = 0;
123 }
124 for (i = 0; i <= numAnimSteps + numAnimSteps; i++) {
125 normalize(animVec[0][i][1]);
126 animVec[0][i][0][0] = 1;
127 animVec[0][i][0][1] = 0;
128 animVec[0][i][0][2] = 0;
129 vecProd(animVec[0][i][2], animVec[0][i][0], animVec[0][i][1]);
130
131 normalize(animVec[1][i][0]);
132 animVec[1][i][1][0] = 0;

Pagina 266 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

133 animVec[1][i][1][1] = 1;
134 animVec[1][i][1][2] = 0;
135 vecProd(animVec[1][i][2], animVec[1][i][0], animVec[1][i][1]);
136
137 normalize(animVec[2][i][0]);
138 animVec[2][i][2][0] = 0;
139 animVec[2][i][2][1] = 0;
140 animVec[2][i][2][2] = 1;
141 vecProd(animVec[2][i][1], animVec[2][i][2], animVec[2][i][0]);
142
143 normalize(animVec[3][i][1]);
144 animVec[3][i][0][0] = 1;
145 animVec[3][i][0][1] = 0;
146 animVec[3][i][0][2] = 0;
147 vecProd(animVec[3][i][2], animVec[3][i][0], animVec[3][i][1]);
148
149 normalize(animVec[4][i][0]);
150 animVec[4][i][1][0] = 0;
151 animVec[4][i][1][1] = 1;
152 animVec[4][i][1][2] = 0;
153 vecProd(animVec[4][i][2], animVec[4][i][0], animVec[4][i][1]);
154
155 normalize(animVec[5][i][0]);
156 animVec[5][i][2][0] = 0;
157 animVec[5][i][2][1] = 0;
158 animVec[5][i][2][2] = 1;
159 vecProd(animVec[5][i][1], animVec[5][i][2], animVec[5][i][0]);
160 }
161 reset();
162 }
163
164 public void reset() {
165 eye[0][0] = 0.9f;
166 eye[0][1] = 0;
167 eye[0][2] = -0.4359f;
168 eye[1][0] = 0.19f;
169 eye[1][1] = 0.9f;
170 eye[1][2] = 0.3923f;
171 vecProd(eye[2], eye[0], eye[1]);
172 repaint();
173 }
174
175 boolean twisting = false;
176 int twistMove, twistDir;
177
178 public void run() {
179 // run animation
180 animCube(twistMove, twistDir);
181 // do actual move
182 cubieSettings.cubePos.doMove(twistMove, twistDir, false);
183 repaint();
184 doEvent(eventType);
185 eventType = true;
186 twisting = false;
187 }
188
189 float animEye[][][] = new float[3][3][3];
190 int anim = 0;
191 int axisOrder[] = { 0, 1, 2 };
192
193 public void animCube(int m, int q) {
194 int i, j, k, d;
195 int animDir[] = { 0, 0, 0 };
196 int animStep[] = { 0, 0, 0 };
197 int animAmount[] = { 0, 0, 0 };
198 d = 0;

Pagina 267 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

199 if (q < 0) {
200 q = -q;
201 d = 3;
202 }
203 // initialise animation variables
204 for (i = 0; i < 3; i++) {
205 for (j = 0; j < 3; j++)
206 for (k = 0; k < 3; k++)
207 animEye[i][j][k] = eye[j][k];
208 animAmount[i] = animStep[i] = animDir[i] = 0;
209 }
210
211 // m=6-8, middle layer turn
212 // m=9-11, cube turn
213 // m=12-14, slice move
214 // m=15-17, anti-slice move
215
216 if (m < 3) {// face move LUF
217 animStep[0] = q;
218 animDir[0] = m + d;
219 axisOrder[0] = m;
220 } else if (m < 6) {// face move RDB
221 animStep[2] = q;
222 animDir[2] = m - d;
223 axisOrder[0] = m - 3;
224 } else if (m < 9) {// midslice move
225 animStep[1] = q;
226 animDir[1] = m - 6 + d;
227 axisOrder[0] = m - 6;
228 } else if (m < 12) {// whole cube move
229 axisOrder[0] = m - 9;
230 animStep[0] = animStep[1] = animStep[2] = q;
231 animDir[0] = animDir[1] = animDir[2] = m - 9 + d;
232 } else if (m < 15) {// slice move
233 axisOrder[0] = m - 12;
234 animStep[0] = animStep[2] = q;
235 animDir[0] = m - 12 + d;
236 animDir[2] = m - 12 + d;
237 } else if (m < 18) {// anti-slice move
238 axisOrder[0] = m - 15;
239 animStep[0] = animStep[2] = q;
240 animDir[0] = m - 15 + d;
241 animDir[2] = m - 15 + 3 - d;
242 }
243
244 // set order of axes - main axis first
245 if (axisOrder[0] == 0) {
246 axisOrder[0] = 0;
247 axisOrder[1] = 1;
248 axisOrder[2] = 2;
249 } else if (axisOrder[0] == 1) {
250 axisOrder[0] = 1;
251 axisOrder[1] = 2;
252 axisOrder[2] = 0;
253 } else {
254 axisOrder[0] = 2;
255 axisOrder[1] = 0;
256 axisOrder[2] = 1;
257 i = animStep[0];
258 animStep[0] = animStep[2];
259 animStep[2] = i;
260 i = animDir[0];
261 animDir[0] = animDir[2];
262 animDir[2] = i;
263 }
264

Pagina 268 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

265 for (j = 1; j < numAnimSteps; j++) {


266 for (i = 0; i < 3; i++) { // for each layer
267 // move a bit
268 animAmount[i] += animStep[i];
269 // calculate animEye for this layer
270 rotateVecs(animEye[i], animVec[animDir[i]][animAmount[i]]);
271 }
272 anim = j;
273 repaint();
274 try {
275 Thread.sleep(15);
276 } catch (Exception ignored) {
277 }
278 }
279 // if middle later has moved, the turn the eye to new position
280 if (animStep[1] != 0) {
281 animAmount[1] += animStep[1];
282 rotateVecs(animEye[0], animVec[animDir[1]][animAmount[1]]);
283 for (i = 0; i < 3; i++)
284 for (j = 0; j < 3; j++)
285 eye[i][j] = animEye[0][i][j];
286
287 }
288 anim = 0;
289 }
290
291 float statEye[][][] = { eye, eye, eye };
292
293 public void paint(Graphics g) {
294 if (offImage == null) {
295 initialise();
296 }
297 offGraphics.setColor(getBackground()); // Clear drawing buffer
298 offGraphics.fillRect(0, 0, width, height);
299 cubieSettings.cubePos.getFaceletColors();
300 if (anim == 0) {
301 drawCube(statEye);
302 } else {
303 drawCube(animEye);
304 }
305 // draw result
306 g.drawImage(offImage, 0, 0, this);
307 }
308
309 // draw cube using the three views eyeVecs for three layers
310 // along the axis axisOrder[0].
311 private void drawCube(float eyeVecs[][][]) {
312 int i, i0, i1, i2;
313 int coord[] = new int[3];
314 int axisDir[] = new int[3];
315 // clear previous mouse areas
316 for (i = 0; i < 54; i++)
317 faceletsO[i] = null;
318
319 // draw the 27 cubelets layer by layer
320
321 // check axis direction of main axis
322 if (eyeVecs[0][2][axisOrder[0]] > 0) {
323 axisDir[axisOrder[0]] = 1;
324 coord[axisOrder[0]] = 0;
325 } else {
326 axisDir[axisOrder[0]] = -1;
327 coord[axisOrder[0]] = 2;
328 }
329
330 // loop over all blocks to draw them

Pagina 269 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

331 for (i0 = 0; i0 < 3; i0++) { // for each layer


332 // recalculate the axis directions for other two axes
333 // necessary since may differ by layer if in mid turn
334 for (i = 1; i < 3; i++) {
335 if (eyeVecs[coord[axisOrder[0]]][2][axisOrder[i]] > 0) {
336 axisDir[axisOrder[i]] = 1;
337 coord[axisOrder[i]] = 0;
338 } else {
339 axisDir[axisOrder[i]] = -1;
340 coord[axisOrder[i]] = 2;
341 }
342 }
343
344 // draw layer
345 for (i1 = 0; i1 < 3; i1++) {
346 for (i2 = 0; i2 < 3; i2++) {
347 drawCubelet(coord, eyeVecs[coord[axisOrder[0]]]);
348 coord[axisOrder[2]] += axisDir[axisOrder[2]];
349 }
350 coord[axisOrder[2]] -= 3 * axisDir[axisOrder[2]];
351 coord[axisOrder[1]] += axisDir[axisOrder[1]];
352 }
353 coord[axisOrder[1]] -= 3 * axisDir[axisOrder[1]];
354 coord[axisOrder[0]] += axisDir[axisOrder[0]];
355 }
356 }
357
358 // draw subcube (cx,cy,cz) under viewing direction vw[][]
359 float ccorn[] = new float[3];
360
361 private void drawCubelet(int cr[], float vw[][]) {
362 int c = cr[0] + cr[1] * 9 + cr[2] * 3;
363 // if(c>3) return;
364 ccorn[0] = cr[0] - 1.5f;
365 ccorn[1] = cr[1] - 1.5f;
366 ccorn[2] = cr[2] - 1.5f;
367
368 // draw right/left
369 if (vw[2][0] > 0) {
370 // draw right
371 ccorn[0]++;
372 ccorn[2]++;
373 drawFacelet(ccorn, coordVec[1], coordVec[5], coordVec[0], vw,
374 facelets[c][3]);
375 ccorn[0]--;
376 ccorn[2]--;
377 } else {
378 // draw left
379 drawFacelet(ccorn, coordVec[1], coordVec[2], coordVec[0], vw,
380 facelets[c][0]);
381 }
382 // draw top/bottom
383 if (vw[2][1] > 0) {
384 // draw bottom
385 ccorn[1]++;
386 ccorn[2]++;
387 drawFacelet(ccorn, coordVec[5], coordVec[0], coordVec[1], vw,
388 facelets[c][4]);
389 ccorn[1]--;
390 ccorn[2]--;
391 } else {
392 // draw top
393 drawFacelet(ccorn, coordVec[2], coordVec[0], coordVec[1], vw,
394 facelets[c][1]);
395 }
396 // draw front/back

Pagina 270 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

397 if (vw[2][2] > 0) {


398 // draw front
399 ccorn[2]++;
400 drawFacelet(ccorn, coordVec[1], coordVec[0], coordVec[2], vw,
401 facelets[c][2]);
402 ccorn[2]--;
403 } else {
404 // draw back
405 ccorn[0]++;
406 drawFacelet(ccorn, coordVec[1], coordVec[3], coordVec[2], vw,
407 facelets[c][5]);
408 ccorn[0]--;
409 }
410 }
411
412 float vr[] = new float[3];
413 int rectx[] = new int[6];
414 int recty[] = new int[6];
415
416 private void drawFacelet(float corn[], float d1[], float d2[], float d0[],
417 float vw[][], int fl) {
418 int i;
419
420 int br = (int) (dotProd(d0, vw[2]) * 20);
421 if (br < 0)
422 br = -br;
423 if (br > 19)
424 br = 19;
425
426 for (i = 0; i < 4; i++) {
427 // get facelet corner coordinate
428 vr[0] = corn[0];
429 vr[1] = corn[1];
430 vr[2] = corn[2];
431 if (i == 1 || i == 2) {
432 vr[0] += d1[0];
433 vr[1] += d1[1];
434 vr[2] += d1[2];
435 }
436 if (i >= 2) {
437 vr[0] += d2[0];
438 vr[1] += d2[1];
439 vr[2] += d2[2];
440 }
441
442 // project onto viewer plane
443 rectx[i] = OFFSETX + (int) (dotProd(vr, vw[0]) * radius);
444 recty[i] = OFFSETY + (int) (dotProd(vr, vw[1]) * radius);
445 }
446 offGraphics.setColor(fgColor[6][br]);
447 offGraphics.fillPolygon(rectx, recty, 4);
448
449 int br2 = (int) (dotProd(d1, vw[2]) * 20);
450 if (br2 < 0)
451 br2 = -br2;
452 if (br2 > 19)
453 br2 = 19;
454 offGraphics.setColor(fgColor[7][19 - br2]);
455 offGraphics.drawLine(rectx[0], recty[0], rectx[1], recty[1]);
456 offGraphics.drawLine(rectx[2], recty[2], rectx[3], recty[3]);
457 br2 = (int) (dotProd(d2, vw[2]) * 20);
458 if (br2 < 0)
459 br2 = -br2;
460 if (br2 > 19)
461 br2 = 19;
462 offGraphics.setColor(fgColor[7][19 - br2]);

Pagina 271 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

463 offGraphics.drawLine(rectx[3], recty[3], rectx[0], recty[0]);


464 offGraphics.drawLine(rectx[1], recty[1], rectx[2], recty[2]);
465
466 if (fl < 0)
467 return; // done if was internal facelet
468
469 // store facelet as polygon for processing mouse
470 // actions later
471 faceletsO[fl] = new Polygon(rectx, recty, 4);
472 moveDirs[fl][0] = dotProd(d1, vw[0]);
473 moveDirs[fl][1] = dotProd(d1, vw[1]);
474 moveDirs[fl][2] = dotProd(d2, vw[0]);
475 moveDirs[fl][3] = dotProd(d2, vw[1]);
476
477 int cl = cubieSettings.cubePos.cubeletPerm[20
478 + cubieSettings.cubePos.faceletColor[fl]] - 20;
479
480 for (i = 0; i < 4; i++) {
481 // get facelet corner coordinate
482 vr[0] = corn[0] + 0.1f * (d1[0] + d2[0]);
483 vr[1] = corn[1] + 0.1f * (d1[1] + d2[1]);
484 vr[2] = corn[2] + 0.1f * (d1[2] + d2[2]);
485 if (i == 1 || i == 2) {
486 vr[0] += .8f * d1[0];
487 vr[1] += .8f * d1[1];
488 vr[2] += .8f * d1[2];
489 }
490 if (i >= 2) {
491 vr[0] += .8f * d2[0];
492 vr[1] += .8f * d2[1];
493 vr[2] += .8f * d2[2];
494 }
495
496 // project onto viewer plane
497 rectx[i] = OFFSETX + (int) (dotProd(vr, vw[0]) * radius);
498 recty[i] = OFFSETY + (int) (dotProd(vr, vw[1]) * radius);
499 }
500 offGraphics.setColor(fgColor[cl][br]);
501 offGraphics.fillPolygon(rectx, recty, 4);
502
503 if (cubieSettings.superGroup) {
504 cl = cubieSettings.cubePos.faceletOri[fl];
505 if (cl == 0) {
506 addpnt(corn, d1, d2, vw, 0, 0.5f, 0.3f);
507 addpnt(corn, d1, d2, vw, 1, 0.5f, 0.7f);
508 addpnt(corn, d1, d2, vw, 2, 0.05f, 0.7f);
509 addpnt(corn, d1, d2, vw, 3, 0.05f, 0.3f);
510 } else if (cl == 1) {
511 addpnt(corn, d1, d2, vw, 0, 0.3f, 0.5f);
512 addpnt(corn, d1, d2, vw, 1, 0.7f, 0.5f);
513 addpnt(corn, d1, d2, vw, 2, 0.7f, 0.05f);
514 addpnt(corn, d1, d2, vw, 3, 0.3f, 0.05f);
515 } else if (cl == 2) {
516 addpnt(corn, d1, d2, vw, 0, 0.5f, 0.3f);
517 addpnt(corn, d1, d2, vw, 1, 0.5f, 0.7f);
518 addpnt(corn, d1, d2, vw, 2, 0.95f, 0.7f);
519 addpnt(corn, d1, d2, vw, 3, 0.95f, 0.3f);
520 } else if (cl == 3) {
521 addpnt(corn, d1, d2, vw, 0, 0.3f, 0.5f);
522 addpnt(corn, d1, d2, vw, 1, 0.7f, 0.5f);
523 addpnt(corn, d1, d2, vw, 2, 0.7f, 0.95f);
524 addpnt(corn, d1, d2, vw, 3, 0.3f, 0.95f);
525 }
526 offGraphics.setColor(fgColor[6][br]);
527 offGraphics.fillPolygon(rectx, recty, 4);
528 }

Pagina 272 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

529 }
530
531 private void addpnt(float corn[], float d1[], float d2[], float vw[][], int i,
532 float x, float y) {
533 // get facelet corner coordinate
534 vr[0] = corn[0] + x * d1[0] + y * d2[0];
535 vr[1] = corn[1] + x * d1[1] + y * d2[1];
536 vr[2] = corn[2] + x * d1[2] + y * d2[2];
537 // project onto viewer plane
538 rectx[i] = OFFSETX + (int) (dotProd(vr, vw[0]) * radius);
539 recty[i] = OFFSETY + (int) (dotProd(vr, vw[1]) * radius);
540 }
541
542 // normalize vetor, i.e. scale it to length 1
543 private void normalize(float v[]) {
544 float l = (float) Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
545 v[0] /= l;
546 v[1] /= l;
547 v[2] /= l;
548 }
549
550 // dot (inner vector) product
551 private float dotProd(float v[], float w[]) {
552 return (v[0] * w[0] + v[1] * w[1] + v[2] * w[2]);
553 }
554
555 // cross (outer vector) product
556 private void vecProd(float u[], float v[], float w[]) {
557 u[0] = v[1] * w[2] - v[2] * w[1];
558 u[1] = v[2] * w[0] - v[0] * w[2];
559 u[2] = v[0] * w[1] - v[1] * w[0];
560 }
561
562 // Consider Eye coords along new axes v[] and return new eye in old coords
563 private void rotateVecs(float res[][], float v[][]) {
564 int i, j;
565 for (i = 0; i < 3; i++) {
566 for (j = 0; j < 3; j++) {
567 res[i][j] = v[0][j] * eye[i][0] + v[1][j] * eye[i][1]
568 + v[2][j] * eye[i][2];
569 }
570 }
571 }
572
573 // --- mouse routines ---
574 // conversion from facelet mouse move to internal move number
575 final int moves[][] = {
576 { -2, -2, -2, -8, -11, -8, 5, 5, 5, -6, -6, -6, 9, 12, 9, 3, 3, 3, -2, -2,
577 -2, -8, -11, -8, 5, 5, 5, -2, -2, -2, -8, -11, -8, 5, 5, 5, -3, -3,
578 -3, -9, -12, -9, 6, 6, 6, -2, -2, -2, -8, -11, -8, 5, 5, 5 },
579 { -6, 9, 3, -6, 12, 3, -6, 9, 3, -1, -7, 4, -1, -10, 4, -1, -7, 4, -1, -7,
580 4, -1, -10, 4, -1, -7, 4, -3, -9, 6, -3, -12, 6, -3, -9, 6, -1, -7, 4,
581 -1, -10, 4, -1, -7, 4, -4, 7, 1, -4, 10, 1, -4, 7, 1 },
582 { 2, 2, 2, 8, 11, 8, -5, -5, -5, 6, 6, 6, -9, -12, -9, -3, -3, -3, 2, 2,
583 2, 8, 11, 8, -5, -5, -5, 2, 2, 2, 8, 11, 8, -5, -5, -5, 3, 3, 3, 9,
584 12, 9, -6, -6, -6, 2, 2, 2, 8, 11, 8, -5, -5, -5 },
585 { 6, -9, -3, 6, -12, -3, 6, -9, -3, 1, 7, -4, 1, 10, -4, 1, 7, -4, 1, 7,
586 -4, 1, 10, -4, 1, 7, -4, 3, 9, -6, 3, 12, -6, 3, 9, -6, 1, 7, -4, 1,
587 10, -4, 1, 7, -4, 4, -7, -1, 4, -10, -1, 4, -7, -1 } };
588
589 // return facelet number belonging to coordinate x,y
590 protected int getFacelet(int x, int y) {
591 for (int k = 0; k < 54; k++) {
592 if (faceletsO[k] != null && faceletsO[k].contains(x, y)) {
593 return (k);
594 }

Pagina 273 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

595 }
596 return (-1);
597 }
598
599 // perform move of facelet f in direction x,y
600 private void executeMouseMove(int f, int x, int y) {
601 int d = -1, m;
602 // compare x,y with the stored vectors
603 if (f < 0)
604 return;
605 float f1 = x * moveDirs[f][1] - y * moveDirs[f][0];
606 float f2 = x * moveDirs[f][3] - y * moveDirs[f][2];
607 if (f1 > f2 && f1 > -f2)
608 d = 0;
609 else if (f1 < f2 && f1 < -f2)
610 d = 2;
611 else if (f2 > f1 && f2 > -f1)
612 d = 1;
613 else if (f2 < f1 && f2 < -f1)
614 d = 3;
615 if (d >= 0 && f >= 0) {
616 m = moves[d][f];
617 if (m < 0) {
618 tryMove(-m - 1, -1);
619 } else {
620 tryMove(m - 1, 1);
621 }
622 }
623 }
624
625 void doMove(int m, int q) {
626 if (!cubieSettings.lockViewer)
627 doMove2(m, q);
628 }
629
630 void doMove2(int m, int q) {
631 if (!twisting) {
632 twisting = true;
633 twistMove = m;
634 twistDir = q;
635 new Thread(this).start();
636 }
637 }
638
639 public boolean showMove(int face, int qu) {
640 if (twisting)
641 return (false);
642 if (qu > 2)
643 qu -= 4;
644 eventType = false; // set flag to show this is not initiated by user
645 doMove2(face, qu);
646 return (true);
647 }
648
649 // Check if mouse move to coord x,y is far enough to trigger a move.
650 protected void checkMouseMove(int x, int y, int d) {
651 if (lastF < 0) { // mousepress was not on a facelet
652 // rotate whole cube
653 int dx = x - lastX;
654 int dy = y - lastY;
655 lastX = x;
656 lastY = y;
657 float f = (float) dx / radius / 2;
658 eye[0][0] += f * eye[2][0];
659 eye[0][1] += f * eye[2][1];
660 eye[0][2] += f * eye[2][2];

Pagina 274 van 329 CubeThesis™ Depamelaere-Deschuytter


class Viewer3D

661 normalize(eye[0]);
662 vecProd(eye[2], eye[0], eye[1]);
663 f = (float) dy / radius / 2;
664 eye[1][0] += f * eye[2][0];
665 eye[1][1] += f * eye[2][1];
666 eye[1][2] += f * eye[2][2];
667 normalize(eye[1]);
668 vecProd(eye[2], eye[0], eye[1]);
669 repaint();
670 } else { // haven't yet moved
671 int dx, dy;
672 dx = x - lastX; // horizontal shift
673 dy = y - lastY; // vertical shift
674 if (dx * dx + dy * dy > d) {
675 executeMouseMove(getFacelet(lastX, lastY), dx, dy);
676 moved = true;
677 }
678 }
679 }
680 }

Pagina 275 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerBox

1 package solver.solverJS.viewSolverJS;
2
3 import java.awt.*;
4 import java.awt.event.*;
5
6 import solver.solverJS.algorithm.*;
7
8 final class ViewerBox extends Viewer {
9 // --- Display routines ---
10
11 private static final long serialVersionUID = 1L;
12 // graphical representation data
13 int CELL, BORD, OFFSETX, OFFSETY;
14 Polygon faceletsI[];
15 Polygon faceletsO[];
16 Polygon faceOriMarks[][];
17
18 public ViewerBox(int x, int y, CubieSettings s, ActionListener m) {
19 super(x, y, s, m);
20 int i, j, c;
21 CELL = x / 16;
22 BORD = y / 16;
23 if (BORD < CELL)
24 CELL = BORD;
25 BORD = 2;
26 OFFSETX = (x - 16 * CELL) / 2;
27 OFFSETY = (y - 16 * CELL) / 2;
28 faceletsI = new Polygon[54];
29 faceletsO = new Polygon[54];
30 faceOriMarks = new Polygon[54][4];
31
32 for (c = 0; c < 54; c++) {
33 faceletsI[c] = new Polygon();
34 faceletsO[c] = new Polygon();
35 for (i = 0; i < 4; i++)
36 faceOriMarks[c][i] = new Polygon();
37 }
38 c = 0;
39 // L
40 for (j = 0; j < 3; j++)
41 for (i = 0; i < 3; i++) {
42 doFacelet(CELL * (4 - i), CELL * (4 - i) + (CELL * (8 + 2 * i) * j) / 3,
43 CELL * (5 - i), CELL * (5 - i) + (CELL * (6 + 2 * i) * j) / 3,
44 CELL * (5 - i), CELL * (5 - i) + (CELL * (6 + 2 * i) * (j + 1)) / 3,
45 CELL * (4 - i), CELL * (4 - i) + (CELL * (8 + 2 * i) * (j + 1)) / 3,
46 BORD, 2 * BORD * (3 - j) / 3, -BORD, 2 * BORD * j / 3, -BORD,
47 2 * BORD * (j - 2) / 3, BORD, -2 * BORD * (j + 1) / 3, c);
48 c++;
49 }
50 // U
51 for (j = 0; j < 3; j++)
52 for (i = 0; i < 3; i++) {
53 doFacelet(CELL * (5 - j) + (CELL * (6 + 2 * j) * (i + 1)) / 3,
54 CELL * (5 - j), CELL * (5 - j) + (CELL * (6 + 2 * j) * i) / 3,
55 CELL * (5 - j), CELL * (4 - j) + (CELL * (8 + 2 * j) * i) / 3,
56 CELL * (4 - j), CELL * (4 - j) + (CELL * (8 + 2 * j) * (i + 1)) / 3,
57 CELL * (4 - j), 2 * BORD * (i - 2) / 3, -BORD, 2 * BORD * i / 3,
58 -BORD, 2 * BORD * (3 - i) / 3, BORD, -2 * BORD * (i + 1) / 3, BORD,
59 c);
60 c++;
61 }
62 // F
63 faceletsO[c].addPoint(0, 0);
64 faceletsO[c].addPoint(6 * CELL, 0);
65 faceletsO[c].addPoint(6 * CELL, 2 * CELL);
66 faceletsO[c].addPoint(2 * CELL, 2 * CELL);

Pagina 276 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerBox

67 faceletsO[c].addPoint(2 * CELL, 6 * CELL);


68 faceletsO[c].addPoint(0, 6 * CELL);
69
70 faceletsI[c].addPoint(BORD, BORD);
71 faceletsI[c].addPoint(6 * CELL - BORD, BORD);
72 faceletsI[c].addPoint(6 * CELL - BORD, 2 * CELL - BORD);
73 faceletsI[c].addPoint(2 * CELL - BORD, 2 * CELL - BORD);
74 faceletsI[c].addPoint(2 * CELL - BORD, 6 * CELL - BORD);
75 faceletsI[c].addPoint(BORD, 6 * CELL - BORD);
76 // top marker
77 faceOriMarks[c][0].addPoint((4 * CELL + BORD) / 2, 0);
78 faceOriMarks[c][0].addPoint((8 * CELL - BORD) / 2, 0);
79 faceOriMarks[c][0].addPoint((8 * CELL - BORD) / 2, CELL);
80 faceOriMarks[c][0].addPoint((4 * CELL + BORD) / 2, CELL);
81 // right marker
82 faceOriMarks[c][3].addPoint(4 * CELL, (CELL + BORD) / 2);
83 faceOriMarks[c][3].addPoint(6 * CELL, (CELL + BORD) / 2);
84 faceOriMarks[c][3].addPoint(6 * CELL, (3 * CELL - BORD) / 2);
85 faceOriMarks[c][3].addPoint(4 * CELL, (3 * CELL - BORD) / 2);
86 // bottom marker
87 faceOriMarks[c][2].addPoint((CELL + BORD) / 2, 4 * CELL);
88 faceOriMarks[c][2].addPoint((3 * CELL - BORD) / 2, 4 * CELL);
89 faceOriMarks[c][2].addPoint((3 * CELL - BORD) / 2, 6 * CELL);
90 faceOriMarks[c][2].addPoint((CELL + BORD) / 2, 6 * CELL);
91 // left marker
92 faceOriMarks[c][1].addPoint(0, (4 * CELL + BORD) / 2);
93 faceOriMarks[c][1].addPoint(CELL, (4 * CELL + BORD) / 2);
94 faceOriMarks[c][1].addPoint(CELL, (8 * CELL - BORD) / 2);
95 faceOriMarks[c][1].addPoint(0, (8 * CELL - BORD) / 2);
96 c++;
97 doFacelet(10 * CELL, 0, 6 * CELL, 0, 6 * CELL, 2 * CELL, 10 * CELL,
98 2 * CELL, -BORD, BORD, BORD, BORD, BORD, -BORD, -BORD, -BORD, c);
99 c++;
100 faceletsO[c].addPoint(10 * CELL, 0);
101 faceletsO[c].addPoint(16 * CELL, 0);
102 faceletsO[c].addPoint(16 * CELL, 6 * CELL);
103 faceletsO[c].addPoint(14 * CELL, 6 * CELL);
104 faceletsO[c].addPoint(14 * CELL, 2 * CELL);
105 faceletsO[c].addPoint(10 * CELL, 2 * CELL);
106 faceletsI[c].addPoint(10 * CELL + BORD, BORD);
107 faceletsI[c].addPoint(16 * CELL - BORD, BORD);
108 faceletsI[c].addPoint(16 * CELL - BORD, 6 * CELL - BORD);
109 faceletsI[c].addPoint(14 * CELL + BORD, 6 * CELL - BORD);
110 faceletsI[c].addPoint(14 * CELL + BORD, 2 * CELL - BORD);
111 faceletsI[c].addPoint(10 * CELL + BORD, 2 * CELL - BORD);
112 // top marker
113 faceOriMarks[c][0].addPoint((24 * CELL + BORD) / 2, 0);
114 faceOriMarks[c][0].addPoint((28 * CELL - BORD) / 2, 0);
115 faceOriMarks[c][0].addPoint((28 * CELL - BORD) / 2, CELL);
116 faceOriMarks[c][0].addPoint((24 * CELL + BORD) / 2, CELL);
117 // right marker
118 faceOriMarks[c][3].addPoint(15 * CELL, (4 * CELL + BORD) / 2);
119 faceOriMarks[c][3].addPoint(16 * CELL, (4 * CELL + BORD) / 2);
120 faceOriMarks[c][3].addPoint(16 * CELL, (8 * CELL - BORD) / 2);
121 faceOriMarks[c][3].addPoint(15 * CELL, (8 * CELL - BORD) / 2);
122 // bottom marker
123 faceOriMarks[c][2].addPoint((29 * CELL + BORD) / 2, 4 * CELL);
124 faceOriMarks[c][2].addPoint((31 * CELL - BORD) / 2, 4 * CELL);
125 faceOriMarks[c][2].addPoint((31 * CELL - BORD) / 2, 6 * CELL);
126 faceOriMarks[c][2].addPoint((29 * CELL + BORD) / 2, 6 * CELL);
127 // left marker
128 faceOriMarks[c][1].addPoint(10 * CELL, (CELL + BORD) / 2);
129 faceOriMarks[c][1].addPoint(12 * CELL, (CELL + BORD) / 2);
130 faceOriMarks[c][1].addPoint(12 * CELL, (3 * CELL - BORD) / 2);
131 faceOriMarks[c][1].addPoint(10 * CELL, (3 * CELL - BORD) / 2);
132 c++;

Pagina 277 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerBox

133 doFacelet(2 * CELL, 6 * CELL, 0, 6 * CELL, 0, 10 * CELL, 2 * CELL,


134 10 * CELL, -BORD, BORD, BORD, BORD, BORD, -BORD, -BORD, -BORD, c);
135 c++;
136 c++;
137 doFacelet(16 * CELL, 6 * CELL, 14 * CELL, 6 * CELL, 14 * CELL, 10 * CELL,
138 16 * CELL, 10 * CELL, -BORD, BORD, BORD, BORD, BORD, -BORD, -BORD,
139 -BORD, c);
140 c++;
141 faceletsO[c].addPoint(0, 10 * CELL);
142 faceletsO[c].addPoint(2 * CELL, 10 * CELL);
143 faceletsO[c].addPoint(2 * CELL, 14 * CELL);
144 faceletsO[c].addPoint(6 * CELL, 14 * CELL);
145 faceletsO[c].addPoint(6 * CELL, 16 * CELL);
146 faceletsO[c].addPoint(0, 16 * CELL);
147 faceletsI[c].addPoint(BORD, 10 * CELL + BORD);
148 faceletsI[c].addPoint(2 * CELL - BORD, 10 * CELL + BORD);
149 faceletsI[c].addPoint(2 * CELL - BORD, 14 * CELL + BORD);
150 faceletsI[c].addPoint(6 * CELL - BORD, 14 * CELL + BORD);
151 faceletsI[c].addPoint(6 * CELL - BORD, 16 * CELL - BORD);
152 faceletsI[c].addPoint(BORD, 16 * CELL - BORD);
153 // top marker
154 faceOriMarks[c][0].addPoint((CELL + BORD) / 2, 10 * CELL);
155 faceOriMarks[c][0].addPoint((CELL + BORD) / 2, 12 * CELL);
156 faceOriMarks[c][0].addPoint((3 * CELL - BORD) / 2, 12 * CELL);
157 faceOriMarks[c][0].addPoint((3 * CELL - BORD) / 2, 10 * CELL);
158 // right marker
159 faceOriMarks[c][3].addPoint(4 * CELL, (29 * CELL + BORD) / 2);
160 faceOriMarks[c][3].addPoint(4 * CELL, (31 * CELL - BORD) / 2);
161 faceOriMarks[c][3].addPoint(6 * CELL, (31 * CELL - BORD) / 2);
162 faceOriMarks[c][3].addPoint(6 * CELL, (29 * CELL + BORD) / 2);
163 // bottom marker
164 faceOriMarks[c][2].addPoint((4 * CELL + BORD) / 2, 15 * CELL);
165 faceOriMarks[c][2].addPoint((4 * CELL + BORD) / 2, 16 * CELL);
166 faceOriMarks[c][2].addPoint((8 * CELL - BORD) / 2, 16 * CELL);
167 faceOriMarks[c][2].addPoint((8 * CELL - BORD) / 2, 15 * CELL);
168 // left marker
169 faceOriMarks[c][1].addPoint(0, (24 * CELL + BORD) / 2);
170 faceOriMarks[c][1].addPoint(0, (28 * CELL - BORD) / 2);
171 faceOriMarks[c][1].addPoint(CELL, (28 * CELL - BORD) / 2);
172 faceOriMarks[c][1].addPoint(CELL, (24 * CELL + BORD) / 2);
173 c++;
174 doFacelet(10 * CELL, 14 * CELL, 6 * CELL, 14 * CELL, 6 * CELL, 16 * CELL,
175 10 * CELL, 16 * CELL, -BORD, BORD, BORD, BORD, BORD, -BORD, -BORD,
176 -BORD, c);
177 c++;
178 faceletsO[c].addPoint(14 * CELL, 10 * CELL);
179 faceletsO[c].addPoint(16 * CELL, 10 * CELL);
180 faceletsO[c].addPoint(16 * CELL, 16 * CELL);
181 faceletsO[c].addPoint(10 * CELL, 16 * CELL);
182 faceletsO[c].addPoint(10 * CELL, 14 * CELL);
183 faceletsO[c].addPoint(14 * CELL, 14 * CELL);
184 faceletsI[c].addPoint(14 * CELL + BORD, 10 * CELL + BORD);
185 faceletsI[c].addPoint(16 * CELL - BORD, 10 * CELL + BORD);
186 faceletsI[c].addPoint(16 * CELL - BORD, 16 * CELL - BORD);
187 faceletsI[c].addPoint(10 * CELL + BORD, 16 * CELL - BORD);
188 faceletsI[c].addPoint(10 * CELL + BORD, 14 * CELL + BORD);
189 faceletsI[c].addPoint(14 * CELL + BORD, 14 * CELL + BORD);
190 // top marker
191 faceOriMarks[c][0].addPoint((29 * CELL + BORD) / 2, 10 * CELL);
192 faceOriMarks[c][0].addPoint((29 * CELL + BORD) / 2, 12 * CELL);
193 faceOriMarks[c][0].addPoint((31 * CELL - BORD) / 2, 12 * CELL);
194 faceOriMarks[c][0].addPoint((31 * CELL - BORD) / 2, 10 * CELL);
195 // right marker
196 faceOriMarks[c][3].addPoint(16 * CELL, (24 * CELL + BORD) / 2);
197 faceOriMarks[c][3].addPoint(16 * CELL, (28 * CELL - BORD) / 2);
198 faceOriMarks[c][3].addPoint(15 * CELL, (28 * CELL - BORD) / 2);

Pagina 278 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerBox

199 faceOriMarks[c][3].addPoint(15 * CELL, (24 * CELL + BORD) / 2);


200 // bottom marker
201 faceOriMarks[c][2].addPoint((24 * CELL + BORD) / 2, 15 * CELL);
202 faceOriMarks[c][2].addPoint((24 * CELL + BORD) / 2, 16 * CELL);
203 faceOriMarks[c][2].addPoint((28 * CELL - BORD) / 2, 16 * CELL);
204 faceOriMarks[c][2].addPoint((28 * CELL - BORD) / 2, 15 * CELL);
205 // left marker
206 faceOriMarks[c][1].addPoint(10 * CELL, (29 * CELL + BORD) / 2);
207 faceOriMarks[c][1].addPoint(10 * CELL, (31 * CELL - BORD) / 2);
208 faceOriMarks[c][1].addPoint(12 * CELL, (31 * CELL - BORD) / 2);
209 faceOriMarks[c][1].addPoint(12 * CELL, (29 * CELL + BORD) / 2);
210 c++;
211 // R
212 for (j = 0; j < 3; j++)
213 for (i = 0; i < 3; i++) {
214 doFacelet(CELL * (13 - i),
215 CELL * (3 + i) + (CELL * (10 - 2 * i) * j) / 3, CELL * (14 - i),
216 CELL * (2 + i) + (CELL * (12 - 2 * i) * j) / 3, CELL * (14 - i),
217 CELL * (2 + i) + (CELL * (12 - 2 * i) * (j + 1)) / 3,
218 CELL * (13 - i),
219 CELL * (3 + i) + (CELL * (10 - 2 * i) * (j + 1)) / 3, +BORD,
220 2 * BORD * j / 3, -BORD, 2 * BORD * (3 - j) / 3, -BORD,
221 -2 * BORD * (j + 1) / 3, +BORD, 2 * BORD * (j - 2) / 3, c);
222 c++;
223 }
224 // D
225 for (j = 0; j < 3; j++)
226 for (i = 0; i < 3; i++) {
227 doFacelet(CELL * (2 + j) + (CELL * (12 - 2 * j) * (i + 1)) / 3,
228 CELL * (14 - j), CELL * (2 + j) + (CELL * (12 - 2 * j) * i) / 3,
229 CELL * (14 - j), CELL * (3 + j) + (CELL * (10 - 2 * j) * i) / 3,
230 CELL * (13 - j),
231 CELL * (3 + j) + (CELL * (10 - 2 * j) * (i + 1)) / 3,
232 CELL * (13 - j), -2 * BORD * (i + 1) / 3, -BORD,
233 2 * BORD * (3 - i) / 3, -BORD, 2 * BORD * i / 3, BORD,
234 2 * BORD * (i - 3) / 3, BORD, c);
235 c++;
236 }
237 // B
238 for (j = 0; j < 3; j++)
239 for (i = 0; i < 3; i++) {
240 doFacelet(CELL * (9 - 2 * i), CELL * (5 + 2 * j), CELL * (11 - 2 * i),
241 CELL * (5 + 2 * j), CELL * (11 - 2 * i), CELL * (7 + 2 * j),
242 CELL * (9 - 2 * i), CELL * (7 + 2 * j), BORD, BORD, -BORD, BORD,
243 -BORD, -BORD, BORD, -BORD, c);
244 c++;
245 }
246
247 for (c = 0; c < 54; c++) {
248 faceletsI[c].translate(OFFSETX, OFFSETY);
249 faceletsO[c].translate(OFFSETX, OFFSETY);
250 for (i = 0; i < 4; i++)
251 faceOriMarks[c][i].translate(OFFSETX, OFFSETY);
252 }
253 }
254
255 private void doFacelet(int x1, int y1, int x2, int y2, int x3, int y3, int x4,
256 int y4, int d1, int e1, int d2, int e2, int d3, int e3, int d4, int e4,
257 int c) {
258 faceletsO[c].addPoint(x1, y1);
259 faceletsO[c].addPoint(x2, y2);
260 faceletsO[c].addPoint(x3, y3);
261 faceletsO[c].addPoint(x4, y4);
262 faceletsI[c].addPoint(x1 + d1, y1 + e1);
263 faceletsI[c].addPoint(x2 + d2, y2 + e2);
264 faceletsI[c].addPoint(x3 + d3, y3 + e3);

Pagina 279 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerBox

265 faceletsI[c].addPoint(x4 + d4, y4 + e4);


266 // do top marker
267 faceOriMarks[c][0].addPoint(((x1 + d1) * 3 + (x2 + d2) + 2) / 4,
268 ((y1 + e1) * 3 + (y2 + e2) + 2) / 4);
269 faceOriMarks[c][0].addPoint(((x1 + d1) + 3 * (x2 + d2) + 2) / 4,
270 ((y1 + e1) + 3 * (y2 + e2) + 2) / 4);
271 faceOriMarks[c][0].addPoint(
272 ((x1 + d1 + x4 + d4) + 3 * (x2 + d2 + x3 + d3) + 4) / 8,
273 ((y1 + e1 + y4 + e4) + 3 * (y2 + e2 + y3 + e3) + 4) / 8);
274 faceOriMarks[c][0].addPoint(
275 ((x1 + d1 + x4 + d4) * 3 + (x2 + d2 + x3 + d3) + 4) / 8,
276 ((y1 + e1 + y4 + e4) * 3 + (y2 + e2 + y3 + e3) + 4) / 8);
277 // do right marker
278 faceOriMarks[c][1].addPoint(((x2 + d2) * 3 + (x3 + d3) + 2) / 4,
279 ((y2 + e2) * 3 + (y3 + e3) + 2) / 4);
280 faceOriMarks[c][1].addPoint(((x2 + d2) + 3 * (x3 + d3) + 2) / 4,
281 ((y2 + e2) + 3 * (y3 + e3) + 2) / 4);
282 faceOriMarks[c][1].addPoint(
283 ((x2 + d2 + x1 + d1) + 3 * (x3 + d3 + x4 + d4) + 4) / 8,
284 ((y2 + e2 + y1 + e1) + 3 * (y3 + e3 + y4 + e4) + 4) / 8);
285 faceOriMarks[c][1].addPoint(
286 ((x2 + d2 + x1 + d1) * 3 + (x3 + d3 + x4 + d4) + 4) / 8,
287 ((y2 + e2 + y1 + e1) * 3 + (y3 + e3 + y4 + e4) + 4) / 8);
288 // do bottom marker
289 faceOriMarks[c][2].addPoint(((x3 + d3) * 3 + (x4 + d4) + 2) / 4,
290 ((y3 + e3) * 3 + (y4 + e4) + 2) / 4);
291 faceOriMarks[c][2].addPoint(((x3 + d3) + 3 * (x4 + d4) + 2) / 4,
292 ((y3 + e3) + 3 * (y4 + e4) + 2) / 4);
293 faceOriMarks[c][2].addPoint(
294 ((x3 + d3 + x2 + d2) + 3 * (x4 + d4 + x1 + d1) + 4) / 8,
295 ((y3 + e3 + y2 + e2) + 3 * (y4 + e4 + y1 + e1) + 4) / 8);
296 faceOriMarks[c][2].addPoint(
297 ((x3 + d3 + x2 + d2) * 3 + (x4 + d4 + x1 + d1) + 4) / 8,
298 ((y3 + e3 + y2 + e2) * 3 + (y4 + e4 + y1 + e1) + 4) / 8);
299 // do left marker
300 faceOriMarks[c][3].addPoint(((x4 + d4) * 3 + (x1 + d1) + 2) / 4,
301 ((y4 + e4) * 3 + (y1 + e1) + 2) / 4);
302 faceOriMarks[c][3].addPoint(((x4 + d4) + 3 * (x1 + d1) + 2) / 4,
303 ((y4 + e4) + 3 * (y1 + e1) + 2) / 4);
304 faceOriMarks[c][3].addPoint(
305 ((x4 + d4 + x3 + d3) + 3 * (x1 + d1 + x2 + d2) + 4) / 8,
306 ((y4 + e4 + y3 + e3) + 3 * (y1 + e1 + y2 + e2) + 4) / 8);
307 faceOriMarks[c][3].addPoint(
308 ((x4 + d4 + x3 + d3) * 3 + (x1 + d1 + x2 + d2) + 4) / 8,
309 ((y4 + e4 + y3 + e3) * 3 + (y1 + e1 + y2 + e2) + 4) / 8);
310 }
311
312 public void paint(Graphics g) {
313 if (offImage == null) {
314 initialise();
315 }
316 offGraphics.setColor(getBackground()); // Clear drawing buffer
317 offGraphics.fillRect(0, 0, width, height);
318 offGraphics.setColor(baseColor); // draw cube base
319 offGraphics.fillRect(OFFSETX, OFFSETY, 16 * CELL, 16 * CELL);
320 // draw cube
321 cubieSettings.cubePos.getFaceletColors();
322 for (int c = 0; c < 54; c++) { // each facelet
323 offGraphics.setColor(colors[cubieSettings.cubePos.cubeletPerm[20
324 + cubieSettings.cubePos.faceletColor[c]] - 20]); // draw facelet
325 offGraphics.fillPolygon(faceletsI[c]);
326 if (cubieSettings.superGroup) {
327 offGraphics.setColor(baseColor);
328 offGraphics
329 .fillPolygon(faceOriMarks[c][cubieSettings.cubePos.faceletOri[c]]);
330 }

Pagina 280 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerBox

331 }
332 g.drawImage(offImage, 0, 0, this);
333 }
334
335 // --- mouse routines ---
336 // conversion from facelet mouse move to internal move number
337 final int moves[][] = {
338 { 2, 2, 2, 8, 11, 8, -5, -5, -5, -6, -6, -6, 9, 12, 9, 3, 3, 3, -2, -2,
339 -2, -8, -11, -8, 5, 5, 5, 2, 2, 2, 8, 11, 8, -5, -5, -5, -3, -3, -3,
340 -9, -12, -9, 6, 6, 6, 2, 2, 2, 8, 11, 8, -5, -5, -5 },
341 { 6, -9, -3, 6, -12, -3, 6, -9, -3, -1, -7, 4, -1, -10, 4, -1, -7, 4, 1,
342 7, -4, 1, 10, -4, 1, 7, -4, 3, 9, -6, 3, 12, -6, 3, 9, -6, -1, -7, 4,
343 -1, -10, 4, -1, -7, 4, 4, -7, -1, 4, -10, -1, 4, -7, -1 },
344 { -2, -2, -2, -8, -11, -8, 5, 5, 5, 6, 6, 6, -9, -12, -9, -3, -3, -3, 2,
345 2, 2, 8, 11, 8, -5, -5, -5, -2, -2, -2, -8, -11, -8, 5, 5, 5, 3, 3, 3,
346 9, 12, 9, -6, -6, -6, -2, -2, -2, -8, -11, -8, 5, 5, 5 },
347 { -6, 9, 3, -6, 12, 3, -6, 9, 3, 1, 7, -4, 1, 10, -4, 1, 7, -4, -1, -7, 4,
348 -1, -10, 4, -1, -7, 4, -3, -9, 6, -3, -12, 6, -3, -9, 6, 1, 7, -4, 1,
349 10, -4, 1, 7, -4, -4, 7, 1, -4, 10, 1, -4, 7, 1 } };
350
351 // Check if mouse move to coord x,y is far enough to trigger a move.
352 protected void checkMouseMove(int x, int y, int d) {
353 if (!moved) {
354 int dx, dy;
355 dx = x - lastX; // horizontal shift
356 dy = y - lastY; // vertical shift
357 if (dx * dx + dy * dy > d) {
358 executeMouseMove(getFacelet(lastX, lastY), dx, dy);
359 moved = true;
360 }
361 }
362 }
363
364 // return facelet number belonging to coordinate x,y
365 protected int getFacelet(int x, int y) {
366 for (int k = 0; k < 54; k++) {
367 if (faceletsO[k].contains(x, y)) {
368 return (k);
369 }
370 }
371 return (-1);
372 }
373
374 // perform move of facelet f in direction x,y
375 private void executeMouseMove(int f, int x, int y) {
376 int d = -1, m;
377 if (x > y && x > -y)
378 d = 0;
379 else if (x < y && x < -y)
380 d = 2;
381 else if (y > x && y > -x)
382 d = 1;
383 else if (y < x && y < -x)
384 d = 3;
385 if (d >= 0 && f >= 0) {
386 m = moves[d][f];
387 if (m < 0) {
388 tryMove(-m - 1, -1);
389 } else {
390 tryMove(m - 1, 1);
391 }
392 }
393 }
394 }
1

Pagina 281 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerDiag

1 package solver.solverJS.viewSolverJS;
2
3 import java.awt.*;
4 import java.awt.event.*;
5
6 import solver.solverJS.algorithm.*;
7
8 final class ViewerDiag extends Viewer {
9 // --- Display routines ---
10
11 private static final long serialVersionUID = 1L;
12 // graphical representation data
13 Polygon faceletsI[] = new Polygon[54];
14 Polygon faceletsO[] = new Polygon[54];
15 Polygon faceOriMarks[][] = new Polygon[54][4];
16 Polygon cubeBack[] = new Polygon[4];
17
18 public ViewerDiag(int x, int y, CubieSettings s, ActionListener m) {
19 super(x, y, s, m);
20 int i, c;
21 int FACEH, CELLH, FACEV, CELLV, FACEL, CELLL, OFFSETX, OFFSETY;
22 // vert : 8.5*CELLV+5.5*CELLL == 21.15*CELLV
23 // FACEL/FACEV=2.3, vert=2*FACEL+3*FACEV
24 // FACEH/FACEV=2
25 CELLV = (int) ((double) y / 21.15);
26 i = x / 22;
27 if (i < CELLV)
28 CELLV = i;
29 CELLH = CELLV * 2;
30 CELLL = (int) (2.3 * CELLV);
31 FACEH = 3 * CELLH;
32 FACEL = 3 * CELLL;
33 FACEV = 3 * CELLV;
34
35 OFFSETX = (x - 11 * CELLH) / 2;
36 OFFSETY = (y + y - 11 * CELLL - 17 * CELLV) / 4;
37 for (c = 0; c < 54; c++) {
38 faceletsI[c] = new Polygon();
39 faceletsO[c] = new Polygon();
40 for (i = 0; i < 4; i++)
41 faceOriMarks[c][i] = new Polygon();
42 }
43 double b = 7. / FACEL;
44
45 // get the correct shape of each face
46 dopoly(FACEH, 0, -FACEH, FACEV, 0, FACEL, 0, b);// L
47 dopoly(FACEH * 2 - CELLH / 2, FACEL - FACEV - (CELLL - CELLV) / 2, FACEH,
48 FACEV, -FACEH, FACEV, 9, b);// U
49 dopoly(FACEH - CELLH / 2, FACEL - (CELLL - CELLV) / 2, FACEH, FACEV, 0,
50 FACEL, 18, b);// F
51 dopoly(FACEH * 2 - CELLH / 2, FACEL + FACEV - (CELLL - CELLV) / 2, FACEH,
52 -FACEV, 0, FACEL, 27, b);// R
53 dopoly(FACEH - CELLH / 2, FACEV * 2 + FACEL * 2 - (CELLL + CELLV) / 2,
54 FACEH, FACEV, FACEH, -FACEV, 36, b);// D
55 dopoly(FACEH * 4 - CELLH, FACEV, -FACEH, -FACEV, 0, FACEL, 45, b);// B
56
57 // shift into position
58 for (c = 0; c < 54; c++) {
59 faceletsI[c].translate(OFFSETX, OFFSETY);
60 faceletsO[c].translate(OFFSETX, OFFSETY);
61 for (i = 0; i < 4; i++)
62 faceOriMarks[c][i].translate(OFFSETX, OFFSETY);
63 }
64
65 // get background of the cube, the areas to be filled black.
66 for (c = 0; c < 4; c++)

Pagina 282 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerDiag

67 cubeBack[c] = new Polygon();


68
69 cubeBack[0].addPoint(0, 0);// FUR
70 cubeBack[0].addPoint(0, FACEL);
71 cubeBack[0].addPoint(FACEH, FACEL + FACEV);
72 cubeBack[0].addPoint(FACEH * 2, FACEL);
73 cubeBack[0].addPoint(FACEH * 2, 0);
74 cubeBack[0].addPoint(FACEH, -FACEV);
75 cubeBack[0].translate(OFFSETX + FACEH - CELLH / 2,
76 OFFSETY + FACEL - (CELLL - CELLV) / 2);
77
78 cubeBack[1].addPoint(FACEH, 0);// L
79 cubeBack[1].addPoint(0, FACEV);
80 cubeBack[1].addPoint(0, FACEV + FACEL);
81 cubeBack[1].addPoint(FACEH, FACEL);
82 cubeBack[1].translate(OFFSETX, OFFSETY);
83
84 cubeBack[2].addPoint(0, -FACEV);// D
85 cubeBack[2].addPoint(-FACEH, 0);
86 cubeBack[2].addPoint(0, FACEV);
87 cubeBack[2].addPoint(FACEH, 0);
88 cubeBack[2].translate(OFFSETX + FACEH * 2 - CELLH / 2,
89 OFFSETY + FACEL * 2 + FACEV * 2 - (CELLL + CELLV) / 2);
90
91 cubeBack[3].addPoint(0, FACEL);// B
92 cubeBack[3].addPoint(FACEH, FACEL + FACEV);
93 cubeBack[3].addPoint(FACEH, FACEV);
94 cubeBack[3].addPoint(0, 0);
95 cubeBack[3].translate(OFFSETX + FACEH * 3 - CELLH, OFFSETY);
96
97 }
98
99 private void dopoly(int x0, int y0, int dx1, int dy1, int dx2, int dy2, int c,
100 double b) {
101 for (int j = 0; j < 3; j++)
102 for (int i = 0; i < 3; i++) {
103 // build outer facelet
104 faceletsO[c].addPoint(i * dx1 / 3 + j * dx2 / 3,
105 i * dy1 / 3 + j * dy2 / 3);
106 faceletsO[c].addPoint((i + 1) * dx1 / 3 + j * dx2 / 3,
107 (i + 1) * dy1 / 3 + j * dy2 / 3);
108 faceletsO[c].addPoint((i + 1) * dx1 / 3 + (j + 1) * dx2 / 3,
109 (i + 1) * dy1 / 3 + (j + 1) * dy2 / 3);
110 faceletsO[c].addPoint(i * dx1 / 3 + (j + 1) * dx2 / 3,
111 i * dy1 / 3 + (j + 1) * dy2 / 3);
112 faceletsO[c].translate(x0, y0);
113 // build inner facelet (i.e. sticker)
114 faceletsI[c].addPoint((int) ((b + i) * dx1 / 3 + (b + j) * dx2 / 3),
115 (int) ((b + i) * dy1 / 3 + (b + j) * dy2 / 3));
116 faceletsI[c].addPoint(
117 (int) ((-b + i + 1) * dx1 / 3 + (b + j) * dx2 / 3),
118 (int) ((-b + i + 1) * dy1 / 3 + (b + j) * dy2 / 3));
119 faceletsI[c].addPoint(
120 (int) ((-b + i + 1) * dx1 / 3 + (-b + j + 1) * dx2 / 3),
121 (int) ((-b + i + 1) * dy1 / 3 + (-b + j + 1) * dy2 / 3));
122 faceletsI[c].addPoint(
123 (int) ((b + i) * dx1 / 3 + (-b + j + 1) * dx2 / 3),
124 (int) ((b + i) * dy1 / 3 + (-b + j + 1) * dy2 / 3));
125 faceletsI[c].translate(x0, y0);
126 // build top marker
127 faceOriMarks[c][0].addPoint(
128 (int) ((i + b / 2 + .25) * dx1 / 3 + (j) * dx2 / 3),
129 (int) ((i + b / 2 + .25) * dy1 / 3 + (j) * dy2 / 3));
130 faceOriMarks[c][0].addPoint(
131 (int) ((i - b / 2 + .75) * dx1 / 3 + (j) * dx2 / 3),
132 (int) ((i - b / 2 + .75) * dy1 / 3 + (j) * dy2 / 3));

Pagina 283 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerDiag

133 faceOriMarks[c][0].addPoint(
134 (int) ((i - b / 2 + .75) * dx1 / 3 + (j + .5) * dx2 / 3),
135 (int) ((i - b / 2 + .75) * dy1 / 3 + (j + .5) * dy2 / 3));
136 faceOriMarks[c][0].addPoint(
137 (int) ((i + b / 2 + .25) * dx1 / 3 + (j + .5) * dx2 / 3),
138 (int) ((i + b / 2 + .25) * dy1 / 3 + (j + .5) * dy2 / 3));
139 faceOriMarks[c][0].translate(x0, y0);
140 // build right marker
141 faceOriMarks[c][3].addPoint(
142 (int) ((i + .5) * dx1 / 3 + (j + b / 2 + .25) * dx2 / 3),
143 (int) ((i + .5) * dy1 / 3 + (j + b / 2 + .25) * dy2 / 3));
144 faceOriMarks[c][3].addPoint(
145 (int) ((i + 1) * dx1 / 3 + (j + b / 2 + .25) * dx2 / 3),
146 (int) ((i + 1) * dy1 / 3 + (j + b / 2 + .25) * dy2 / 3));
147 faceOriMarks[c][3].addPoint(
148 (int) ((i + 1) * dx1 / 3 + (j - b / 2 + .75) * dx2 / 3),
149 (int) ((i + 1) * dy1 / 3 + (j - b / 2 + .75) * dy2 / 3));
150 faceOriMarks[c][3].addPoint(
151 (int) ((i + .5) * dx1 / 3 + (j - b / 2 + .75) * dx2 / 3),
152 (int) ((i + .5) * dy1 / 3 + (j - b / 2 + .75) * dy2 / 3));
153 faceOriMarks[c][3].translate(x0, y0);
154 // build bottom marker
155 faceOriMarks[c][2].addPoint(
156 (int) ((i + b / 2 + .25) * dx1 / 3 + (j + .5) * dx2 / 3),
157 (int) ((i + b / 2 + .25) * dy1 / 3 + (j + .5) * dy2 / 3));
158 faceOriMarks[c][2].addPoint(
159 (int) ((i - b / 2 + .75) * dx1 / 3 + (j + .5) * dx2 / 3),
160 (int) ((i - b / 2 + .75) * dy1 / 3 + (j + .5) * dy2 / 3));
161 faceOriMarks[c][2].addPoint(
162 (int) ((i - b / 2 + .75) * dx1 / 3 + (j + 1) * dx2 / 3),
163 (int) ((i - b / 2 + .75) * dy1 / 3 + (j + 1) * dy2 / 3));
164 faceOriMarks[c][2].addPoint(
165 (int) ((i + b / 2 + .25) * dx1 / 3 + (j + 1) * dx2 / 3),
166 (int) ((i + b / 2 + .25) * dy1 / 3 + (j + 1) * dy2 / 3));
167 faceOriMarks[c][2].translate(x0, y0);
168 // build left marker
169 faceOriMarks[c][1].addPoint(
170 (int) ((i) * dx1 / 3 + (j + b / 2 + .25) * dx2 / 3),
171 (int) ((i) * dy1 / 3 + (j + b / 2 + .25) * dy2 / 3));
172 faceOriMarks[c][1].addPoint(
173 (int) ((i + .5) * dx1 / 3 + (j + b / 2 + .25) * dx2 / 3),
174 (int) ((i + .5) * dy1 / 3 + (j + b / 2 + .25) * dy2 / 3));
175 faceOriMarks[c][1].addPoint(
176 (int) ((i + .5) * dx1 / 3 + (j - b / 2 + .75) * dx2 / 3),
177 (int) ((i + .5) * dy1 / 3 + (j - b / 2 + .75) * dy2 / 3));
178 faceOriMarks[c][1].addPoint(
179 (int) ((i) * dx1 / 3 + (j - b / 2 + .75) * dx2 / 3),
180 (int) ((i) * dy1 / 3 + (j - b / 2 + .75) * dy2 / 3));
181 faceOriMarks[c][1].translate(x0, y0);
182
183 c++;
184 }
185 }
186
187 public void paint(Graphics g) {
188 int i;
189 if (offImage == null) {
190 initialise();
191 }
192 offGraphics.setColor(getBackground()); // Clear drawing buffer
193 offGraphics.fillRect(0, 0, width, height);
194 // draw cube
195 cubieSettings.cubePos.getFaceletColors();
196
197 offGraphics.setColor(baseColor); // draw facelet base
198 for (i = 1; i < 4; i++)

Pagina 284 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerDiag

199 offGraphics.fillPolygon(cubeBack[i]);
200
201 for (i = 0; i < 9; i++) { // do L face
202 offGraphics.setColor(colors[cubieSettings.cubePos.cubeletPerm[20
203 + cubieSettings.cubePos.faceletColor[i]] - 20]); // draw facelet
204 offGraphics.fillPolygon(faceletsI[i]);
205 if (cubieSettings.superGroup) {
206 offGraphics.setColor(baseColor);
207 offGraphics
208 .fillPolygon(faceOriMarks[i][cubieSettings.cubePos.faceletOri[i]]);
209 }
210 }
211 for (i = 36; i < 54; i++) { // do R,D faces
212 offGraphics.setColor(colors[cubieSettings.cubePos.cubeletPerm[20
213 + cubieSettings.cubePos.faceletColor[i]] - 20]); // draw facelet
214 offGraphics.fillPolygon(faceletsI[i]);
215 if (cubieSettings.superGroup) {
216 offGraphics.setColor(baseColor);
217 offGraphics
218 .fillPolygon(faceOriMarks[i][cubieSettings.cubePos.faceletOri[i]]);
219 }
220 }
221
222 offGraphics.setColor(baseColor); // draw cube base
223 offGraphics.fillPolygon(cubeBack[0]);
224
225 for (i = 9; i < 36; i++) { // do R,D faces
226 offGraphics.setColor(colors[cubieSettings.cubePos.cubeletPerm[20
227 + cubieSettings.cubePos.faceletColor[i]] - 20]); // draw facelet
228 offGraphics.fillPolygon(faceletsI[i]);
229 if (cubieSettings.superGroup) {
230 offGraphics.setColor(baseColor);
231 offGraphics
232 .fillPolygon(faceOriMarks[i][cubieSettings.cubePos.faceletOri[i]]);
233 }
234 }
235
236 g.drawImage(offImage, 0, 0, this);
237 }
238
239 // --- mouse routines ---
240 // conversion from facelet mouse move to internal move number
241 final int moves[][] = {
242 { -2, -2, -2, -8, -11, -8, 5, 5, 5, -6, -6, -6, 9, 12, 9, 3, 3, 3, -2, -2,
243 -2, -8, -11, -8, 5, 5, 5, 2, 2, 2, 8, 11, 8, -5, -5, -5, -3, -3, -3,
244 -9, -12, -9, 6, 6, 6, 2, 2, 2, 8, 11, 8, -5, -5, -5 },
245 { 6, -9, -3, 6, -12, -3, 6, -9, -3, -1, -7, 4, -1, -10, 4, -1, -7, 4, 1,
246 7, -4, 1, 10, -4, 1, 7, -4, 3, 9, -6, 3, 12, -6, 3, 9, -6, 1, 7, -4,
247 1, 10, -4, 1, 7, -4, 4, -7, -1, 4, -10, -1, 4, -7, -1 },
248 { 2, 2, 2, 8, 11, 8, -5, -5, -5, 6, 6, 6, -9, -12, -9, -3, -3, -3, 2, 2,
249 2, 8, 11, 8, -5, -5, -5, -2, -2, -2, -8, -11, -8, 5, 5, 5, 3, 3, 3, 9,
250 12, 9, -6, -6, -6, -2, -2, -2, -8, -11, -8, 5, 5, 5 },
251 { -6, 9, 3, -6, 12, 3, -6, 9, 3, 1, 7, -4, 1, 10, -4, 1, 7, -4, -1, -7, 4,
252 -1, -10, 4, -1, -7, 4, -3, -9, 6, -3, -12, 6, -3, -9, 6, -1, -7, 4,
253 -1, -10, 4, -1, -7, 4, -4, 7, 1, -4, 10, 1, -4, 7, 1 } };
254
255 // Check if mouse move to coord x,y is far enough to trigger a move.
256 protected void checkMouseMove(int x, int y, int d) {
257 if (!moved) {
258 int dx, dy;
259 dx = x - lastX; // horizontal shift
260 dy = y - lastY; // vertical shift
261 if (dx * dx + dy * dy > d) {
262 executeMouseMove(getFacelet(lastX, lastY), dx, dy);
263 moved = true;
264 }

Pagina 285 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerDiag

265 }
266 }
267
268 // return facelet number belonging to coordinate x,y
269 protected int getFacelet(int x, int y) {
270 int k;
271 for (k = 9; k < 54; k++) {
272 if (faceletsO[k].contains(x, y))
273 return (k);
274 }
275 for (k = 0; k < 9; k++) {
276 if (faceletsO[k].contains(x, y))
277 return (k);
278 }
279 return (-1);
280 }
281
282 // perform move of facelet f in direction x,y
283 private void executeMouseMove(int f, int x, int y) {
284 int d = -1, m;
285 if ((f >= 9 && f < 18) || (f >= 36 && f < 45)) { // U/D facelet
286 if (x > 0 && y > 0)
287 d = 0;
288 else if (x < 0 && y < 0)
289 d = 2;
290 else if (x > 0 && y < 0)
291 d = 1;
292 else if (x < 0 && y > 0)
293 d = 3;
294 } else if ((f >= 18 && f < 27) || (f >= 45 && f < 54)) { // F/B facelet
295 if (x + y + y > 0 && 3 * x > 2 * y)
296 d = 0;
297 else if (x + y + y < 0 && 3 * x < 2 * y)
298 d = 2;
299 else if (x + y + y > 0 && 3 * x < 2 * y)
300 d = 1;
301 else if (x + y + y < 0 && 3 * x > 2 * y)
302 d = 3;
303 } else if ((f >= 0 && f < 9) || (f >= 27 && f < 36)) { // L/R facelet
304 if (y + y > x && 2 * y + 3 * x < 0)
305 d = 0;
306 else if (y + y < x && 2 * y + 3 * x > 0)
307 d = 2;
308 else if (y + y > x && 2 * y + 3 * x > 0)
309 d = 1;
310 else if (y + y < x && 2 * y + 3 * x < 0)
311 d = 3;
312 }
313 if (d >= 0 && f >= 0) {
314 m = moves[d][f];
315 if (m < 0) {
316 tryMove(-m - 1, -1);
317 } else {
318 tryMove(m - 1, 1);
319 }
320 }
321 }
322 }

Pagina 286 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerFlat

1 package solver.solverJS.viewSolverJS;
2
3 import java.awt.*;
4 import java.awt.event.*;
5
6 import solver.solverJS.algorithm.*;
7
8 final class ViewerFlat extends Viewer {
9 private static final long serialVersionUID = 1L;
10 // --- Display routines ---
11
12 // graphical representation data
13 int FACE, CELL, BORD, OFFSETX, OFFSETY;
14 int facecoordX[];
15 int facecoordY[];
16
17 public ViewerFlat(int x, int y, CubieSettings s, ActionListener m) {
18 super(x, y, s, m);
19 CELL = x / 12;
20 FACE = y / 9;
21 if (FACE < CELL)
22 CELL = FACE;
23 FACE = CELL * 3;
24 BORD = 2;
25 OFFSETX = (x - 4 * FACE) / 2;
26 OFFSETY = (y - 3 * FACE) / 2;
27 facecoordX = new int[6];
28 facecoordY = new int[6];
29 facecoordX[0] = OFFSETX + 0;
30 facecoordY[0] = OFFSETY + FACE;
31 facecoordX[1] = OFFSETX + FACE;
32 facecoordY[1] = OFFSETY + 0;
33 facecoordX[2] = OFFSETX + FACE;
34 facecoordY[2] = OFFSETY + FACE;
35 facecoordX[3] = OFFSETX + 2 * FACE;
36 facecoordY[3] = OFFSETY + FACE;
37 facecoordX[4] = OFFSETX + FACE;
38 facecoordY[4] = OFFSETY + 2 * FACE;
39 facecoordX[5] = OFFSETX + 3 * FACE;
40 facecoordY[5] = OFFSETY + FACE;
41 }
42
43 public void paint(Graphics g) {
44 int i, j, k, c;
45 if (offImage == null) {
46 initialise();
47 }
48 offGraphics.setColor(getBackground()); // Clear drawing buffer
49 offGraphics.fillRect(0, 0, width, height);
50 // draw cube
51 cubieSettings.cubePos.getFaceletColors();
52 c = 0;
53 for (k = 0; k < 6; k++) { // each face
54 offGraphics.setColor(baseColor); // first draw cube colour
55 offGraphics.fillRect(facecoordX[k], facecoordY[k], FACE, FACE);
56 for (i = 0; i < 3; i++) { // each row
57 for (j = 0; j < 3; j++) { // each facelet
58 offGraphics.setColor(colors[cubieSettings.cubePos.cubeletPerm[20
59 + cubieSettings.cubePos.faceletColor[c]] - 20]); // draw facelet
60 offGraphics.fillRect(facecoordX[k] + BORD + j * CELL,
61 facecoordY[k] + BORD + i * CELL, CELL - 2 * BORD,
62 CELL - 2 * BORD);
63 if (cubieSettings.superGroup) {
64 offGraphics.setColor(baseColor);
65 if (cubieSettings.cubePos.faceletOri[c] == 0) {
66 offGraphics.fillRect(

Pagina 287 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerFlat

67 facecoordX[k] + BORD + j * CELL + (CELL - BORD * 2) / 4,


68 facecoordY[k] + BORD + i * CELL, CELL / 2 - BORD,
69 CELL / 2 - BORD);
70 } else if (cubieSettings.cubePos.faceletOri[c] == 3) {
71 offGraphics.fillRect(facecoordX[k] + j * CELL + CELL / 2,
72 facecoordY[k] + BORD + i * CELL + (CELL - BORD * 2) / 4,
73 CELL / 2 - BORD, CELL / 2 - BORD);
74 } else if (cubieSettings.cubePos.faceletOri[c] == 2) {
75 offGraphics.fillRect(
76 facecoordX[k] + BORD + j * CELL + (CELL - BORD * 2) / 4,
77 facecoordY[k] + i * CELL + CELL / 2, CELL / 2 - BORD,
78 CELL / 2 - BORD);
79 } else if (cubieSettings.cubePos.faceletOri[c] == 1) {
80 offGraphics.fillRect(facecoordX[k] + j * CELL + BORD,
81 facecoordY[k] + BORD + i * CELL + (CELL - BORD * 2) / 4,
82 CELL / 2 - BORD, CELL / 2 - BORD);
83 }
84 }
85 c++;
86 }
87 }
88 }
89 g.drawImage(offImage, 0, 0, this);
90 }
91
92 // --- mouse routines ---
93 // conversion from facelet mouse move to internal move number
94 final int moves[][] = {
95 { -2, -2, -2, -8, -11, -8, 5, 5, 5, -6, -6, -6, 9, 12, 9, 3, 3, 3, -2, -2,
96 -2, -8, -11, -8, 5, 5, 5, -2, -2, -2, -8, -11, -8, 5, 5, 5, -3, -3,
97 -3, -9, -12, -9, 6, 6, 6, -2, -2, -2, -8, -11, -8, 5, 5, 5 },
98 { 6, -9, -3, 6, -12, -3, 6, -9, -3, 1, 7, -4, 1, 10, -4, 1, 7, -4, 1, 7,
99 -4, 1, 10, -4, 1, 7, -4, 3, 9, -6, 3, 12, -6, 3, 9, -6, 1, 7, -4, 1,
100 10, -4, 1, 7, -4, 4, -7, -1, 4, -10, -1, 4, -7, -1 },
101 { 2, 2, 2, 8, 11, 8, -5, -5, -5, 6, 6, 6, -9, -12, -9, -3, -3, -3, 2, 2,
102 2, 8, 11, 8, -5, -5, -5, 2, 2, 2, 8, 11, 8, -5, -5, -5, 3, 3, 3, 9,
103 12, 9, -6, -6, -6, 2, 2, 2, 8, 11, 8, -5, -5, -5 },
104 { -6, 9, 3, -6, 12, 3, -6, 9, 3, -1, -7, 4, -1, -10, 4, -1, -7, 4, -1, -7,
105 4, -1, -10, 4, -1, -7, 4, -3, -9, 6, -3, -12, 6, -3, -9, 6, -1, -7, 4,
106 -1, -10, 4, -1, -7, 4, -4, 7, 1, -4, 10, 1, -4, 7, 1 } };
107
108 // Check if mouse move to coord x,y is far enough to trigger a move.
109 protected void checkMouseMove(int x, int y, int d) {
110 if (!moved) {
111 int dx, dy;
112 dx = x - lastX; // horizontal shift
113 dy = y - lastY; // vertical shift
114 if (dx * dx + dy * dy > d) {
115 executeMouseMove(getFacelet(lastX, lastY), dx, dy);
116 moved = true;
117 }
118 }
119 }
120
121 // return facelet number belonging to coordinate x,y
122 protected int getFacelet(int x, int y) {
123 int k, f;
124 for (k = 0; k < 6; k++) {
125 if (x >= facecoordX[k] && x < facecoordX[k] + FACE && y >= facecoordY[k]
126 && y < facecoordY[k] + FACE) {
127 f = k * 9 + 3 * (int) ((y - facecoordY[k]) / CELL)
128 + (int) ((x - facecoordX[k]) / CELL);
129 return (f);
130 }
131 }
132 return (-1);

Pagina 288 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewerFlat

133 }
134
135 // perform move of facelet f in direction x,y
136 private void executeMouseMove(int f, int x, int y) {
137 int d = -1, m;
138 if (x > y && x > -y)
139 d = 0;
140 else if (x < y && x < -y)
141 d = 2;
142 else if (y > x && y > -x)
143 d = 1;
144 else if (y < x && y < -x)
145 d = 3;
146 if (d >= 0 && f >= 0) {
147 m = moves[d][f];
148 if (m < 0) {
149 tryMove(-m - 1, -1);
150 } else {
151 tryMove(m - 1, 1);
152 }
153 }
154 }
155 }

Pagina 289 van 329 CubeThesis™ Depamelaere-Deschuytter


class Corner

1 package view.scrollImageView;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 public class Corner extends JComponent {
7 // Source https://docs.oracle.com/javase/tutorial/uiswing/examples/components/
8 // ScrollDemo visited the 20/10/2015.
9 private static final long serialVersionUID = 1L;
10
11 // Instance method:
12 protected void paintComponent(Graphics g) {
13
14 g.setColor(new Color(50, 25, 0));
15 g.fillRect(0, 0, getWidth(), getHeight());
16 }
17 }

Pagina 290 van 329 CubeThesis™ Depamelaere-Deschuytter


class Ruler

1 package view.scrollImageView;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 public class Ruler extends JComponent {
7 // Source https://docs.oracle.com/javase/tutorial/uiswing/examples/components/
8 // ScrollDemo visited the 20/10/2015.
9 private static final long serialVersionUID = 1L;
10 public static final int INCH = Toolkit.getDefaultToolkit()
11 .getScreenResolution();
12 public static final int HORIZONTAL = 0;
13 public static final int VERTICAL = 1;
14 public static final int SIZE = 35;
15
16 public int orientation;
17 public boolean isMetric;
18 private int increment;
19 private int units;
20
21 // Constructors:
22 public Ruler(int o, boolean m) {
23 orientation = o;
24 isMetric = m;
25 setIncrementAndUnits();
26 }
27
28 // Getters:
29 public int getIncrement() {
30 return increment;
31 }
32
33 // Setters:
34 public void setIsMetric(boolean isMetric) {
35 this.isMetric = isMetric;
36 setIncrementAndUnits();
37 repaint();
38 }
39
40 private void setIncrementAndUnits() {
41 if (isMetric) {
42 units = (int) ((double) INCH / (double) 2.54); // dots per centimeter
43 increment = units;
44 } else {
45 units = INCH;
46 increment = units / 2;
47 }
48 }
49
50 public void setPreferredHeight(int ph) {
51 setPreferredSize(new Dimension(SIZE, ph));
52 }
53
54 public void setPreferredWidth(int pw) {
55 setPreferredSize(new Dimension(pw, SIZE));
56 }
57
58 // Instance methods:
59 public boolean isMetric() {
60 return this.isMetric;
61 }
62
63 protected void paintComponent(Graphics g) {
64 Rectangle drawHere = g.getClipBounds();
65
66 // Color clipping area.

Pagina 291 van 329 CubeThesis™ Depamelaere-Deschuytter


class Ruler

67 g.setColor(new Color(55, 25, 0));


68 g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height);
69
70 // The rulers labels.
71 g.setFont(new Font("Century Gothic", Font.PLAIN, 12));
72 g.setColor(Color.GREEN);
73
74 // Some vars we need.
75 int end = 0;
76 int start = 0;
77 int tickLength = 0;
78 String text = null;
79
80 // Use clipping bounds to calculate first and last tick locations.
81 if (orientation == HORIZONTAL) {
82 start = (drawHere.x / increment) * increment;
83 end = (((drawHere.x + drawHere.width) / increment) + 1) * increment;
84 } else {
85 start = (drawHere.y / increment) * increment;
86 end = (((drawHere.y + drawHere.height) / increment) + 1) * increment;
87 }
88
89 // Make a special case of 0 to display the number
90 // within the rule and draw a units label.
91 if (start == 0) {
92 text = Integer.toString(0) + (isMetric ? " cm" : " in");
93 tickLength = 10;
94 if (orientation == HORIZONTAL) {
95 g.drawLine(0, SIZE - 1, 0, SIZE - tickLength - 1);
96 g.drawString(text, 2, 21);
97 } else {
98 g.drawLine(SIZE - 1, 0, SIZE - tickLength - 1, 0);
99 g.drawString(text, 9, 10);
100 }
101 text = null;
102 start = increment;
103 }
104
105 // ticks and labels
106 for (int i = start; i < end; i += increment) {
107 if (i % units == 0) {
108 tickLength = 10;
109 text = Integer.toString(i / units);
110 } else {
111 tickLength = 7;
112 text = null;
113 }
114
115 if (tickLength != 0) {
116 if (orientation == HORIZONTAL) {
117 g.drawLine(i, SIZE - 1, i, SIZE - tickLength - 1);
118 if (text != null)
119 g.drawString(text, i - 3, 21);
120 } else {
121 g.drawLine(SIZE - 1, i, SIZE - tickLength - 1, i);
122 if (text != null)
123 g.drawString(text, 9, i + 3);
124 }
125 }
126 }
127 }
128 }
129

Pagina 292 van 329 CubeThesis™ Depamelaere-Deschuytter


class ScrollablePicture

1 package view.scrollImageView;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6
7 import model.CommonObjects;
8
9 public class ScrollablePicture extends JLabel
10 implements Scrollable, MouseMotionListener {
11 // Source https://docs.oracle.com/javase/tutorial/uiswing/examples/components/
12 // ScrollDemo visited the 20/10/2015.
13 private static final long serialVersionUID = 1L;
14 private int maxUnitIncrement = 1;
15 private boolean missingPicture = false;
16
17 // Constructors:
18 public ScrollablePicture(int m) {
19 super(new ImageIcon());
20 missingPicture = true;
21 setText("There is no image selected to display.");
22 setFont(CommonObjects.getCBTHSettingsList().getFont("guiFont1"));
23 setForeground(Color.DARK_GRAY);
24 setHorizontalAlignment(CENTER);
25 setOpaque(true);
26 setBackground(Color.white);
27
28 maxUnitIncrement = m;
29
30 // Let the user scroll by dragging to outside the window.
31 setAutoscrolls(true); // enable synthetic drag events
32 addMouseMotionListener(this); // handle mouse drags
33 }
34
35 public ScrollablePicture(ImageIcon i, int m) {
36 // Deze constructor wordt waarschijnlijk niet meer gebruikt.
37 super(i);
38
39 maxUnitIncrement = m;
40
41 // Let the user scroll by dragging to outside the window.
42 setAutoscrolls(true); // enable synthetic drag events
43 addMouseMotionListener(this); // handle mouse drags
44 }
45
46 // Getters:
47 public Dimension getPreferredScrollableViewportSize() {
48 return getPreferredSize();
49 }
50
51 public Dimension getPreferredSize() {
52 if (missingPicture) {
53 return new Dimension(636, 340);
54 } else {
55 return super.getPreferredSize();
56 }
57 }
58
59 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation,
60 int direction) {
61 if (orientation == SwingConstants.HORIZONTAL) {
62 return visibleRect.width - maxUnitIncrement;
63 } else {
64 return visibleRect.height - maxUnitIncrement;
65 }
66 }

Pagina 293 van 329 CubeThesis™ Depamelaere-Deschuytter


class ScrollablePicture

67
68 public boolean getScrollableTracksViewportHeight() {
69 return false;
70 }
71
72 public boolean getScrollableTracksViewportWidth() {
73 return false;
74 }
75
76 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
77 int direction) {
78
79 // Get the current position.
80 int currentPosition = 0;
81 if (orientation == SwingConstants.HORIZONTAL) {
82 currentPosition = visibleRect.x;
83 } else {
84 currentPosition = visibleRect.y;
85 }
86
87 // Return the number of pixels between currentPosition
88 // and the nearest tick mark in the indicated direction.
89 if (direction < 0) {
90 int newPosition = currentPosition
91 - (currentPosition / maxUnitIncrement) * maxUnitIncrement;
92 return (newPosition == 0) ? maxUnitIncrement : newPosition;
93 } else {
94 return ((currentPosition / maxUnitIncrement) + 1) * maxUnitIncrement
95 - currentPosition;
96 }
97 }
98
99 // Setters:
100 public void setMaxUnitIncrement(int pixels) {
101 maxUnitIncrement = pixels;
102 }
103
104 // Instance methods:
105 // Methods required by the MouseMotionListener interface:
106 public void mouseDragged(MouseEvent e) {
107 // The user is dragging us, so scroll!
108 Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
109 scrollRectToVisible(r);
110 }
111
112 public void mouseMoved(MouseEvent e) {
113 }
114 }

Pagina 294 van 329 CubeThesis™ Depamelaere-Deschuytter


class ScrollImageJPanel

1 package view.scrollImageView;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import java.awt.image.*;
6 import javax.swing.*;
7
8 public class ScrollImageJPanel extends JPanel implements ItemListener {
9 // Source https://docs.oracle.com/javase/tutorial/uiswing/examples/components/
10 // ScrollDemo visited the 20/10/2015.
11 private static final long serialVersionUID = 1L;
12 private Ruler columnView;
13 private Ruler rowView;
14 private JToggleButton isMetric;
15 private ScrollablePicture picture;
16 private JScrollPane pictureScrollPane;
17
18 // Constructors:
19 public ScrollImageJPanel(BufferedImage bi) {
20 super();
21 this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
22
23 // Create the row and column headers.
24
25 columnView = new Ruler(Ruler.HORIZONTAL, true);
26 rowView = new Ruler(Ruler.VERTICAL, true);
27
28 ImageIcon pic = null;
29 pic = maakImageIcon(bi);
30
31 if (pic != null) {
32 columnView.setPreferredWidth(pic.getIconWidth());
33 rowView.setPreferredHeight(pic.getIconHeight());
34 } else {
35 columnView.setPreferredWidth(665);
36 rowView.setPreferredHeight(340);
37 }
38
39 // Create the corners.
40 JPanel buttonCorner = new JPanel(); // use FlowLayout
41 isMetric = new JToggleButton("cm/in", true);
42 isMetric.setFont(new Font("Arial Narrow", Font.PLAIN, 12));
43 isMetric.setMargin(new Insets(2, 2, 2, 2));
44 isMetric.addItemListener(this);
45 buttonCorner.add(isMetric);
46
47 // Set up the scroll pane.
48 if (pic != null) {
49 picture = new ScrollablePicture(pic, columnView.getIncrement());
50 } else {
51 picture = new ScrollablePicture(columnView.getIncrement());
52 }
53
54 pictureScrollPane = new JScrollPane(picture);
55
56 pictureScrollPane.setPreferredSize(new Dimension(300, 250));
57 pictureScrollPane
58 .setViewportBorder(BorderFactory.createLineBorder(Color.black));
59
60 pictureScrollPane.setColumnHeaderView(columnView);
61 pictureScrollPane.setRowHeaderView(rowView);
62
63 // Set the corners.
64 // In theory, to support internationalization you would change
65 // UPPER_LEFT_CORNER to UPPER_LEADING_CORNER,
66 // LOWER_LEFT_CORNER to LOWER_LEADING_CORNER, and

Pagina 295 van 329 CubeThesis™ Depamelaere-Deschuytter


class ScrollImageJPanel

67 // UPPER_RIGHT_CORNER to UPPER_TRAILING_CORNER. In practice,


68 // bug #4467063 makes that impossible (in 1.4, at least).
69 pictureScrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, buttonCorner);
70 pictureScrollPane.setCorner(JScrollPane.LOWER_LEFT_CORNER, new Corner());
71 pictureScrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER, new Corner());
72
73 // Put it in this panel.
74 add(pictureScrollPane);
75
76 }
77
78 // Instance method:
79 /** This is an ItemListener, applied to the cm/inch button. */
80 public void itemStateChanged(ItemEvent e) {
81 if (e.getStateChange() == ItemEvent.SELECTED) {
82 // Turn it to metric.
83 rowView.setIsMetric(true);
84 columnView.setIsMetric(true);
85 } else {
86 // Turn it to inches.
87 rowView.setIsMetric(false);
88 columnView.setIsMetric(false);
89 }
90 picture.setMaxUnitIncrement(rowView.getIncrement());
91 }
92
93 // Static method:
94 /** Returns an ImageIcon, or null if the path was invalid. */
95 public static ImageIcon maakImageIcon(BufferedImage bi) {
96
97 if (bi != null) {
98 return new ImageIcon(bi);
99 } else {
100
101 return null;
102 }
103 }
104 }

Pagina 296 van 329 CubeThesis™ Depamelaere-Deschuytter


class TransparentSplashScreen

1 package view;
2
3 import java.awt.Dimension;
4 import java.awt.Graphics;
5 import java.awt.Image;
6 import java.awt.Toolkit;
7 import javax.swing.ImageIcon;
8 import javax.swing.JWindow;
9
10 import model.CBTHSettingsList;
11
12 //Source: http://java2everyone.blogspot.be/2009/03/java-transparent-splash-screen.html visited
13 //13/3/2016.
14 public class TransparentSplashScreen extends JWindow {
15 // transparent splashscreen.
16
17 private static final long serialVersionUID = 1L;
18 private Image bi;
19
20 // Constructor:
21 public TransparentSplashScreen(CBTHSettingsList cbthsl,
22 String[] stringComponents) {
23
24 // Get a partly transparent image that will be used as splash screen image.
25 this.bi = Toolkit.getDefaultToolkit()
26 .getImage(cbthsl.makeSysIndepFilePath(stringComponents, 2));
27 ImageIcon ii = new ImageIcon(bi);
28
29 try {
30 int iconWidth = ii.getIconWidth();
31 int iconHeight = ii.getIconHeight();
32
33 // Retrieve the screensize to precisely position the splashscreen.
34 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
35 int screenWidth = (int) screenSize.getWidth();
36 int screenHeight = (int) screenSize.getHeight();
37
38 // To center rounded rectangle on the screen, the splashscreen should be
39 // moved horizontally for an adittional 35px.
40 this.setBounds((screenWidth - iconWidth) / 2 + 35,
41 (screenHeight - iconHeight) / 2, iconWidth, iconHeight);
42
43 } catch (Exception exception) {
44 exception.printStackTrace();
45 }
46 }
47
48 /** Paint transparent image onto JWindow */
49 public void paint(Graphics g) {
50 g.drawImage(bi, 0, 0, this);
51 }
52 }

Pagina 297 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewCubeThesis

1 package view;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6 import javax.swing.border.*;
7
8 import cbthFileChooser.CBTHFileChooser;
9 import connection.conWithRobot.CommunicationRobotThread;
10 import console.ConsoleCommands;
11 import console.ViewConsolePanel;
12 import listeners.cam.T_CAM_LiveStreamItemListener;
13 import listeners.menu.*;
14 import model.*;
15
16 public class ViewCubeThesis extends JFrame {
17
18 private static final long serialVersionUID = 1L;
19 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
20
21 // Declaration of swing components: JPanel
22 private JPanel p_MainJPanel;
23 private JPanel p_PanelUpTabs;
24 private ViewConsolePanel p_PanelDownConsole;
25
26 private ViewTabPanel0Cam p_tabPanelCam;
27 private ViewTabPanel1Img p_tabPanelAfb;
28 private ViewTabPanel2Cub p_tabPanelKub;
29 private ViewTabPanel3Sol p_tabPanelOpl;
30 private ViewTabPanel4Aut p_tabPanelAut;
31
32 // Declaration of swing components: JSplitPane
33 private JSplitPane sp_splitTabsFromConsole;
34
35 // Declaration of swing components: JMenuBar
36 private JMenuBar menuBar;
37
38 // Declaration of swing components: JMenu
39 private JMenu menu_File;
40 private JMenu menu_Console;
41 private JMenu menu_CBTHSettings;
42 private JMenu menu_Help;
43
44 // Declaration of swing components: JMenuItem
45 private JMenuItem menuItem_NewProject;
46 private JMenuItem menuItem_OpenProject;
47 private JMenuItem menuItem_SaveProject;
48 private JMenuItem menuItem_SaveProjectAs;
49 private JMenuItem menuItem_Exit;
50 private JMenuItem menuItem_ClearConsole;
51 private JMenuItem menuItem_ListCommands;
52 private JMenuItem menuItem_CustomizeCBTHSettings;
53 private JMenuItem menuItem_ImportSettingsFromText;
54 private JMenuItem menuItem_ExportSettingsToText;
55 private JMenuItem menuItem_RestoreFactorySettings;
56 private JMenuItem menuItem_About;
57 private JMenuItem menuItem_Manual;
58 private JMenuItem menuItem_OpenJavaDoc;
59
60 // Declaration of swing components: JTabbedPane
61 private JTabbedPane tp_tabbedPane;
62
63 // Declaration of a CBTHFileChooser & a ConsoleCommands.
64 private CBTHFileChooser cbthfc;
65 private ConsoleCommands cc;
66

Pagina 298 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewCubeThesis

67 // Constructor:
68 /**
69 * This constructor build the main Window of CubeThesis.
70 *
71 * @param imgl
72 * The current CBTHImagesList is passed.
73 * @param cfl
74 * The current CubeFacesList is passed.
75 */
76 public ViewCubeThesis(CBTHImagesList imgl, CubeFacesList cfl) {
77
78 this.setLayout(new BorderLayout());
79 this.setTitle("CUBETHESIS 2015-2016");
80
81 String[] iconPath1Comp = { "img", "icon", "RubiksCube220x210.png" };
82 ImageIcon frameCubeThesisLogo = new ImageIcon(
83 cbthsl.makeSysIndepFilePath(iconPath1Comp, 2));
84
85 this.setIconImage(frameCubeThesisLogo.getImage());
86
87 // One object from CBTHFileChooser, will serve for both open/save purposes.
88 this.cbthfc = new CBTHFileChooser();
89
90 // The console panel is created:
91 p_PanelDownConsole = new ViewConsolePanel();
92
93 // To make CubeThesis react on input from the commandPrompt:
94 cc = new ConsoleCommands(imgl, cfl, cbthfc, p_PanelDownConsole);
95
96 p_MainJPanel = new JPanel(new BorderLayout());
97 p_MainJPanel.setBorder(BorderFactory.createTitledBorder(
98 BorderFactory.createLineBorder(Color.GRAY, 1),
99 "© THESIS SIMON DESCHUYTTER & PIETER DEPAMELAERE", TitledBorder.RIGHT,
100 TitledBorder.BELOW_BOTTOM));
101
102 p_PanelUpTabs = new JPanel(new GridLayout());
103 tp_tabbedPane = new JTabbedPane();
104
105 String[] iconPath2Comp = { "img", "icon", "WDLogo30x30OFF.png" };
106 ImageIcon tabicon = new ImageIcon(
107 cbthsl.makeSysIndepFilePath(iconPath2Comp, 2));
108
109 // TabPanels are created, as creating Objects from other ViewClasses.
110 // Some of these constructors are passed model related objects).
111
112 p_tabPanelCam = new ViewTabPanel0Cam(imgl);
113
114 p_tabPanelAfb = new ViewTabPanel1Img(cbthfc, imgl, cfl);
115 imgl.addObserver(p_tabPanelAfb);
116
117 p_tabPanelKub = new ViewTabPanel2Cub(cfl);
118 cfl.addObserver(p_tabPanelKub);
119
120 p_tabPanelOpl = new ViewTabPanel3Sol();
121
122 p_tabPanelAut = new ViewTabPanel4Aut(imgl, cfl);
123
124 // Adding the tabs to the tabbedPane:
125 tp_tabbedPane.addTab("CAMERA", tabicon, p_tabPanelCam, "Tabpanel [CAMERA]");
126 tp_tabbedPane.addTab("IMAGE", tabicon, p_tabPanelAfb, "Tabpanel [IMAGE]");
127 tp_tabbedPane.addTab("CUBE", tabicon, p_tabPanelKub, "Tabpanel [CUBE]");
128 tp_tabbedPane.addTab("ALGORITHMIC SOLVER", tabicon, p_tabPanelOpl,
129 "Tabpanel [ALGORITHMIC SOLVER]");
130 tp_tabbedPane.addTab("AUTOMATIC MODE", tabicon, p_tabPanelAut,
131 "Tabpanel [AUTOMATIC MODE]");
132

Pagina 299 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewCubeThesis

133 // Make sure the tabs can be browsed by little arrowkeys, when the screen
134 // get's to narrow:
135 tp_tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
136
137 // Adding the tabbedPane to the p_PanelUpTabs:
138 p_PanelUpTabs.add(tp_tabbedPane);
139
140 // Splitting the screen vertically, between p_PanelUpTabs &
141 // p_PanelDownConsole.
142 sp_splitTabsFromConsole = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
143 p_PanelUpTabs, p_PanelDownConsole);
144 sp_splitTabsFromConsole.setDividerLocation(425);
145
146 // Create the menuBar with its components:
147 menuBar = new JMenuBar();
148
149 menu_File = new JMenu("File");
150 menu_File.setMnemonic(KeyEvent.VK_F);
151
152 menu_Console = new JMenu("Console");
153 menu_Console.setMnemonic(KeyEvent.VK_C);
154
155 menu_CBTHSettings = new JMenu("CBTH-Settings");
156 menu_CBTHSettings.setMnemonic(KeyEvent.VK_S);
157
158 menu_Help = new JMenu("Help");
159 menu_Help.setMnemonic(KeyEvent.VK_H);
160
161 menuItem_NewProject = new JMenuItem("New project...");
162 menuItem_NewProject.addActionListener(
163 new MenuItemNewProjectListener(imgl, cfl, p_PanelDownConsole));
164
165 menuItem_OpenProject = new JMenuItem("Open project...");
166 menuItem_OpenProject.addActionListener(
167 new MenuItemOpenProjectListener(cbthfc, p_PanelDownConsole));
168
169 menuItem_SaveProject = new JMenuItem("Save project");
170 menuItem_SaveProject.addActionListener(new MenuItemSaveProjectListener());
171
172 menuItem_SaveProjectAs = new JMenuItem("Save project as...");
173 menuItem_SaveProjectAs
174 .addActionListener(new MenuItemSaveAsProjectListener(cbthfc));
175
176 menuItem_Exit = new JMenuItem("Save & exit");
177 menuItem_Exit
178 .addActionListener(new MenuItemExitListener(p_PanelDownConsole));
179
180 menuItem_ClearConsole = new JMenuItem("Flush & Clear");
181 menuItem_ClearConsole.addActionListener(
182 new MenuItemConsoleClearListener(p_PanelDownConsole));
183
184 menuItem_ListCommands = new JMenuItem("Commands...");
185 menuItem_ListCommands.addActionListener(
186 new MenuItemListCommandsListener(p_PanelDownConsole));
187
188 menuItem_CustomizeCBTHSettings = new JMenuItem("Customize settings...");
189 menuItem_CustomizeCBTHSettings
190 .addActionListener(new MenuItemCustomizeSettingsListener());
191
192 menuItem_ImportSettingsFromText = new JMenuItem(
193 "Import settings \u2190 text");
194 menuItem_ImportSettingsFromText
195 .addActionListener(new MenuItemImportSettingsFromText());
196
197 menuItem_ExportSettingsToText = new JMenuItem(
198 "Export settings \u2192 text");

Pagina 300 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewCubeThesis

199 menuItem_ExportSettingsToText
200 .addActionListener(new MenuItemExportSettingsToText());
201
202 menuItem_RestoreFactorySettings = new JMenuItem("Restore factory settings");
203 menuItem_RestoreFactorySettings
204 .setToolTipText("Restores the situation of Simon & Pieter 2015-2016");
205 menuItem_RestoreFactorySettings
206 .addActionListener(new MenuItemRestoreFactorySettings());
207
208 menuItem_About = new JMenuItem("About CubeThesis...");
209 menuItem_About.addActionListener(new MenuItemAboutListener());
210
211 menuItem_OpenJavaDoc = new JMenuItem("Browse JavaDoc...");
212 menuItem_OpenJavaDoc.addActionListener(new MenuItemJavaDocListener());
213 menuItem_OpenJavaDoc.setToolTipText(
214 "The JavaDoc yields an interactive summary of CubeThesis' source code.");
215
216 menuItem_Manual = new JMenuItem("Manual...");
217 menuItem_Manual.addActionListener(new MenuItemUserManualListener());
218
219 // Assembling the menuBar:
220 menu_File.add(menuItem_NewProject);
221 menu_File.add(menuItem_OpenProject);
222 menu_File.add(menuItem_SaveProject);
223 menu_File.add(menuItem_SaveProjectAs);
224 menu_File.addSeparator();
225 menu_File.add(menuItem_Exit);
226
227 menu_Console.add(menuItem_ClearConsole);
228 menu_Console.add(menuItem_ListCommands);
229
230 menu_CBTHSettings.add(menuItem_CustomizeCBTHSettings);
231 menu_CBTHSettings.addSeparator();
232 menu_CBTHSettings.add(menuItem_ImportSettingsFromText);
233 menu_CBTHSettings.add(menuItem_ExportSettingsToText);
234 menu_CBTHSettings.addSeparator();
235 menu_CBTHSettings.add(menuItem_RestoreFactorySettings);
236
237 menu_Help.add(menuItem_Manual);
238 menu_Help.add(menuItem_OpenJavaDoc);
239 menu_Help.addSeparator();
240 menu_Help.add(menuItem_About);
241
242 menuBar.add(menu_File);
243 menuBar.add(menu_Console);
244 menuBar.add(menu_CBTHSettings);
245 menuBar.add(menu_Help);
246
247 // Add the menuBar to the JFrame:
248 this.setJMenuBar(menuBar);
249
250 // Will allow the content to stretch to the available space.
251 p_MainJPanel.add(sp_splitTabsFromConsole, BorderLayout.CENTER);
252 this.add(p_MainJPanel, BorderLayout.CENTER);
253
254 // Elaborated procedure to precisely position the window in the middle of
255 // the screen.
256 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
257 int screenWidth = (int) screenSize.getWidth();
258 int screenHeight = (int) screenSize.getHeight();
259 int minimumWindowWidth = screenWidth / 4;
260 int minimumWindowHeight = 400;
261 int preferredWindowWidth = 1000;// (1000/620 +- golden ratio)
262 int preferredWindowHeight = 620;
263
264 this.setMinimumSize(new Dimension(minimumWindowWidth, minimumWindowHeight));

Pagina 301 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewCubeThesis

265 this.setPreferredSize(
266 new Dimension(preferredWindowWidth, preferredWindowHeight));
267
268 this.setBounds((screenWidth - preferredWindowWidth) / 2,
269 (screenHeight - preferredWindowHeight) / 2, 1000, 620);
270
271 // Disable the closing, when user clicks closebutton, but spawn warning:
272 this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
273 this.addWindowListener(new WindowAdapter() {
274 public void windowClosing(WindowEvent e) {
275 handleClosing();
276 }
277 });
278
279 // The command below will not spawn the window, that is done in the
280 // main-method.
281 this.pack();
282 }
283
284 // Getter:
285 public CBTHFileChooser getCBTHFileChooser() {
286 return this.cbthfc;
287 }
288
289 // Instance methods:
290 /** Here the user's answer on the warning dialog on closing is evaluated. */
291 public void handleClosing() {
292
293 int answer = showWarningMessage();
294
295 switch (answer) {
296 case JOptionPane.YES_OPTION:
297
298 CommunicationRobotThread comRobot = CommonObjects.getCommunicatieRobot();
299 T_CAM_LiveStreamItemListener camLSIL = CommonObjects.getCamLSIL();
300
301 // Communication with the robot is stopped if necessary:
302 if (comRobot.getLinkRobotEstablished()) {
303 comRobot.stopCommunicationRobot();
304 }
305
306 /*
307 * Connection with the camera device is closed. Not correctly closing the
308 * connection leads to the generation of a hs_err_pidxxx.log file.
309 */
310 if (camLSIL.getLinkCamEstablished()) {
311 camLSIL.disconnectFromCapDevice();
312 }
313
314 if (cbthsl.getBoolean("saveCBTHSettingsOnExit")) {
315 // If true, CBTHSettings are exported at this point.
316 cbthsl.exportCBTHSettingsToTXT();
317 }
318
319 // Remaining info is flushed to the LogFiles and footers are written.
320 p_PanelDownConsole.updateLogFilesByFlushConsole(false, true);
321
322 // Exit the program:
323 System.exit(0);
324
325 break;
326
327 case JOptionPane.CLOSED_OPTION:
328 break;
329
330 case JOptionPane.NO_OPTION:

Pagina 302 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewCubeThesis

331 break;
332 }
333 }
334
335 private int showWarningMessage() {
336 String[] buttonLabels = new String[] { "Yes", "No" };
337 String defaultOption = buttonLabels[1];
338 Icon icon = null;
339
340 return JOptionPane.showOptionDialog(this,
341 "Are you sure you want to quit? " + cbthsl.getString("newLine")
342 + "Unsaved progress will be lost.",
343 "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, icon,
344 buttonLabels, defaultOption);
345 }
346 }

Pagina 303 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel0Cam

1 package view;
2
3 import java.awt.*;
4 import javax.swing.*;
5
6 import exceptions.NoSuchSettingFoundException;
7 import model.CBTHImagesList;
8 import model.CBTHSetting;
9 import model.CBTHSettingsList;
10 import model.CommonObjects;
11 import listeners.cam.*;
12 import listeners.aut.B_AUT_CommandToRobotListener;
13
14 public class ViewTabPanel0Cam extends JPanel {
15
16 private static final long serialVersionUID = 1L;
17 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
18 private JSplitPane sp_split;
19 private JPanel p_ControlPanelLeft;
20 private JPanel p_WindowPanelRight;
21 private JPanel p_CBTHSettingsPanel;
22 private JPanel[] p_columnPanel = { new JPanel(new GridLayout(0, 1, 15, 5)),
23 new JPanel(new GridLayout(0, 1, 15, 5)) };;
24
25 private JButton b_CAMERA_ConnectCam;
26 private JToggleButton t_CAMERA_LiveStreamCam;
27 private JButton b_CAMERA_TakePicture;
28 private JButton b_CAMERA_ConnectRobot;
29 private JButton b_CAMERA_CommandToRobot;
30
31 private volatile JLabel l_cameraView;
32
33 // Constructor:
34 public ViewTabPanel0Cam(CBTHImagesList imgl) {
35
36 super(new BorderLayout());
37
38 // Create JComponents:
39 p_ControlPanelLeft = new JPanel();
40 p_ControlPanelLeft
41 .setLayout(new BoxLayout(p_ControlPanelLeft, BoxLayout.PAGE_AXIS));
42
43 p_WindowPanelRight = new JPanel(new BorderLayout());
44
45 l_cameraView = cbthsl.createJLabel(
46 " Toggle \"Camera livestream\" to retrieve a "
47 + "videostream from CaptureDevice.",1);
48 String[] iconPathComp = { "img", "icon", "CAMdfk23g445.png" };
49 l_cameraView
50 .setIcon(new ImageIcon(cbthsl.makeSysIndepFilePath(iconPathComp, 2)));
51
52 p_CBTHSettingsPanel = new JPanel(new BorderLayout());
53
54 String[] cbthSettingNames = { "captureDevice", "ipAddressCamera",
55 "ipAddressRobot", "portNmbrServerSocket" };
56 CBTHSetting cbths = null;
57 VisualCBTHSetting viscbths = null;
58 for (int i = 0; i < cbthSettingNames.length; i++) {
59 try {
60 cbths = cbthsl.seekCBTHSetting(cbthSettingNames[i]);
61 viscbths = cbths.createVCBTHSetting();
62
63 p_columnPanel[0].add(viscbths.getL_CBTHSLabel());
64 p_columnPanel[1].add(viscbths.getTF_CBTHSValue());
65
66 } catch (NoSuchSettingFoundException nssfe) {

Pagina 304 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel0Cam

67 System.err.println(nssfe);
68 }
69 }
70
71 p_CBTHSettingsPanel.add(p_columnPanel[0], BorderLayout.CENTER);
72 p_CBTHSettingsPanel.add(p_columnPanel[1], BorderLayout.LINE_END);
73
74 b_CAMERA_ConnectCam = cbthsl.createJButton("Connect to camera",
75 "Adjusts the capture-device's index.", new B_CAM_ConnectCamListener());
76
77 t_CAMERA_LiveStreamCam = cbthsl.createJToggleButton("Camera livestream",
78 "Tries to open livestream from camera.", false);
79 t_CAMERA_LiveStreamCam.setToolTipText(
80 "Opent een LiveStream van de camera in het rechtervenster.");
81 T_CAM_LiveStreamItemListener lsil = new T_CAM_LiveStreamItemListener(
82 l_cameraView);
83 CommonObjects.setCamLSIL(lsil);
84 t_CAMERA_LiveStreamCam.addItemListener(lsil);
85
86 b_CAMERA_TakePicture = cbthsl.createJButton("Take one picture",
87 "When livestream is toggled, a snapshot is taken.",
88 new B_CAM_TakeAPictureListener(imgl, lsil));
89 b_CAMERA_ConnectRobot = cbthsl.createJButton("Connect to robot",
90 "PC (server tries to establish connection with the robot (client).",
91 new B_CAM_ConnectRobotListener());
92 b_CAMERA_CommandToRobot = cbthsl.createJButton("Command \u2192 robot",
93 "User manually adds commands to robot's instruction-queue.",
94 new B_AUT_CommandToRobotListener());
95
96 // Assembling the p_ControlPanelLeft:
97 p_ControlPanelLeft.add(b_CAMERA_ConnectCam);
98 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
99 p_ControlPanelLeft.add(t_CAMERA_LiveStreamCam);
100 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
101 p_ControlPanelLeft.add(b_CAMERA_TakePicture);
102 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
103 p_ControlPanelLeft.add(b_CAMERA_ConnectRobot);
104 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
105 p_ControlPanelLeft.add(b_CAMERA_CommandToRobot);
106 p_ControlPanelLeft.add(new JLabel("––––––––––––––––––"));
107 p_CBTHSettingsPanel.setMaximumSize(new Dimension(Short.MAX_VALUE,
108 (int) p_CBTHSettingsPanel.getMinimumSize().getHeight()));
109 p_CBTHSettingsPanel.setAlignmentX(LEFT_ALIGNMENT);
110 p_ControlPanelLeft.add(p_CBTHSettingsPanel);
111 p_ControlPanelLeft.add(Box.createVerticalGlue()); // Fill blank space
112
113 p_WindowPanelRight.add(l_cameraView, BorderLayout.CENTER);
114
115 // Making a horizontal JSplitPane between p_ControlPanelLeft and
116 // p_WindowPanelRight.
117 sp_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
118 new JScrollPane(p_ControlPanelLeft,
119 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
120 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
121 new JScrollPane(p_WindowPanelRight));
122 sp_split.setDividerLocation(325);
123
124 this.add(sp_split, BorderLayout.CENTER);
125 }
126
127 // Getter:
128 public JLabel getLabelCamBeeld() {
129 return l_cameraView;
130 }
131 }

Pagina 305 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel1Img

1 package view;
2
3 import java.awt.*;
4 import java.awt.image.*;
5 import java.util.Observable;
6 import java.util.Observer;
7 import javax.swing.*;
8
9 import cbthFileChooser.CBTHFileChooser;
10 import exceptions.NoSuchSettingFoundException;
11 import listeners.img.*;
12 import model.*;
13 import view.scrollImageView.*;
14
15 public class ViewTabPanel1Img extends JPanel implements Observer {
16
17 private static final long serialVersionUID = 1L;
18 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
19 private static Font guiFont1;
20 private CBTHImagesList imgl;
21 private CBTHImage imgTemporary;
22
23 private JSplitPane sp_split;
24 private JPanel p_ControlPanelLeft;
25 private JPanel p_WindowPanelRight;
26
27 private JPanel p_InputImagePanel;
28 private JPanel p_DeleteSavePanel;
29 private JPanel p_CropSpinnersPanel;
30 private JPanel p_CBTHSettingsPanel;
31
32 private JButton b_IMG_BrowseImage;
33 private JButton b_IMG_SaveImages;
34 private JButton b_IMG_DeleteImage;
35 private JButton b_IMG_ColorEstimation;
36 private JButton b_IMG_UpdateCropParams;
37 private JButton b_IMG_ColorCalibration;
38
39 private JComboBox<Object> cb_ImageDropDown;
40
41 private VisualCBTHSetting[] visualCBTHSettingsArray;
42
43 private Object[] cbthImagesList;
44 private S_IMG_CropSpinnersListener cropSpin;
45
46 // Spinners that are being used for the cropping:
47 private JSpinner s_IMG_X_CO;
48 private JSpinner s_IMG_Y_CO;
49 private JSpinner s_IMG_Width;
50 private JSpinner s_IMG_Height;
51
52 // Constructor:
53 public ViewTabPanel1Img(CBTHFileChooser cbthFC, CBTHImagesList imgl,
54 CubeFacesList cfl) {
55
56 super(new BorderLayout());
57
58 guiFont1 = cbthsl.getFont("guiFont1");
59
60 // Create JComponents:
61 p_ControlPanelLeft = new JPanel();
62 p_ControlPanelLeft
63 .setLayout(new BoxLayout(p_ControlPanelLeft, BoxLayout.PAGE_AXIS));
64 p_InputImagePanel = new JPanel(new BorderLayout());
65 p_DeleteSavePanel = new JPanel(new GridLayout(1, 2));
66 p_CropSpinnersPanel = new JPanel();

Pagina 306 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel1Img

67 p_CropSpinnersPanel
68 .setLayout(new BoxLayout(p_CropSpinnersPanel, BoxLayout.PAGE_AXIS));
69 p_CBTHSettingsPanel = new JPanel(new GridLayout(0, 1, 15, 5));
70 p_WindowPanelRight = new JPanel(new BorderLayout());
71
72 // ImagesList is set the subject of the cb_ImageDropDown-ComboBox:
73 cbthImagesList = imgl.getCBTHImages().toArray();
74 cb_ImageDropDown = new JComboBox<Object>(cbthImagesList);
75 cb_ImageDropDown.setFont(guiFont1);
76 cb_ImageDropDown.setEditable(false);
77 cb_ImageDropDown
78 .addItemListener(new Co_IMG_CBTHImagesListDropdownListener(this));
79
80 // WindowPanelRight always remains, but new ScrollImageJPanel-instances
81 // could be added.
82 p_WindowPanelRight.add(new ScrollImageJPanel(null), BorderLayout.CENTER);
83
84 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
85 int screenWidth = (int) screenSize.getWidth();
86 p_InputImagePanel.setMaximumSize(new Dimension(screenWidth, 25));
87 this.imgl = imgl;
88
89 // Creation of JButtons:
90 b_IMG_BrowseImage = cbthsl.createJButton("Browse img...",
91 "Launches pop-up to browse for img-files.",
92 new B_IMG_BrowseImageListener(cbthFC, imgl));
93 b_IMG_SaveImages = cbthsl.createJButton("Save images",
94 "Images from combobox are saved to original/cropped folders "
95 + "in the current project.",
96 new B_IMG_SaveImagesListener());
97 b_IMG_DeleteImage = cbthsl.createJButton("Delete image",
98 "Deletes selected image", new B_IMG_DeleteImageListener(this, imgl));
99 b_IMG_UpdateCropParams = cbthsl.createJButton("Update crop-parameters",
100 "Will update automatic crop-parameters for future snapshots.",
101 new B_IMG_UpdateCropParamListener(this));
102 b_IMG_ColorCalibration = cbthsl.createJButton("Color calibration",
103 "Will adapt color-estimation ranges based on camera-input.",
104 new B_IMG_ColorCalibrationListener());
105 b_IMG_ColorEstimation = cbthsl.createJButton("Color estimation",
106 "Partitions the image in 9 pieces, then performs colors estimation on those facelets.",
107 new B_IMG_ColorEstimationListener(this, cfl));
108
109 // Create crop-spinners:
110 String[] cropSpinToolTips = { "X-co cropped image", "Y-co cropped image",
111 "Width cropped image", "Height cropped image" };
112 s_IMG_X_CO = createCropSpinner(cropSpinToolTips[0]);
113 s_IMG_Y_CO = createCropSpinner(cropSpinToolTips[1]);
114 s_IMG_Width = createCropSpinner(cropSpinToolTips[2]);
115 s_IMG_Height = createCropSpinner(cropSpinToolTips[3]);
116
117 p_CropSpinnersPanel.add(s_IMG_X_CO);
118 p_CropSpinnersPanel.add(s_IMG_Y_CO);
119 p_CropSpinnersPanel.add(s_IMG_Width);
120 p_CropSpinnersPanel.add(s_IMG_Height);
121
122 // Initialize crop-spinners:
123 updateImgCropSpinners(null);
124
125 // Arrangement of some CBTHSettings on this tab:
126 visualCBTHSettingsArray = new VisualCBTHSetting[4];
127
128 try {
129 visualCBTHSettingsArray[0] = cbthsl
130 .seekCBTHSetting("thresholdColorEstimation").createVCBTHSetting();
131 visualCBTHSettingsArray[1] = cbthsl
132 .seekCBTHSetting("extensiveSampleOutprint").createVCBTHSetting();

Pagina 307 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel1Img

133 visualCBTHSettingsArray[2] = cbthsl


134 .seekCBTHSetting("amountOfSamplesPerFacelet").createVCBTHSetting();
135 visualCBTHSettingsArray[3] = cbthsl
136 .seekCBTHSetting("amountOfSampleAveraging").createVCBTHSetting();
137 } catch (NoSuchSettingFoundException nssfe) {
138 System.err.println(nssfe);
139 }
140
141 for (int i = 0; i < visualCBTHSettingsArray.length; i++) {
142 if (visualCBTHSettingsArray[i] != null) {
143 JPanel p_oneSettingPanel = new JPanel();
144 p_oneSettingPanel.setLayout(new BorderLayout());
145
146 p_oneSettingPanel.add(visualCBTHSettingsArray[i].getL_CBTHSLabel(),
147 BorderLayout.CENTER);
148 p_oneSettingPanel.add(visualCBTHSettingsArray[i].getTF_CBTHSValue(),
149 BorderLayout.LINE_END);
150
151 p_CBTHSettingsPanel.add(p_oneSettingPanel);
152 }
153 }
154
155 // Making a horizontal JSplitPane between p_ControlPanelLeft and
156 // p_WindowPanelRight.
157 sp_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
158 new JScrollPane(p_ControlPanelLeft,
159 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
160 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
161 p_WindowPanelRight);
162 sp_split.setDividerLocation(375);
163
164 // Elements are added to the JPanels:
165 p_InputImagePanel.add(cb_ImageDropDown, BorderLayout.CENTER);
166 p_InputImagePanel.add(b_IMG_BrowseImage, BorderLayout.LINE_END);
167 p_InputImagePanel.setAlignmentX(LEFT_ALIGNMENT);
168
169 if (b_IMG_DeleteImage != null && b_IMG_SaveImages != null
170 && p_DeleteSavePanel != null) {
171
172 p_DeleteSavePanel.add(b_IMG_DeleteImage);
173 p_DeleteSavePanel.add(b_IMG_SaveImages);
174 p_DeleteSavePanel.setAlignmentX(LEFT_ALIGNMENT);
175 } else {
176 System.out.println("view images panel null");
177 }
178
179 // Assembling the p_ControlPanelLeft:
180 p_ControlPanelLeft.add(p_InputImagePanel);
181 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 5)));
182 p_DeleteSavePanel.setMaximumSize(new Dimension(Short.MAX_VALUE,
183 (int) p_DeleteSavePanel.getMinimumSize().getHeight()));
184 p_ControlPanelLeft.add(p_DeleteSavePanel);
185 p_CropSpinnersPanel.setMaximumSize(new Dimension(Short.MAX_VALUE,
186 (int) p_CropSpinnersPanel.getMinimumSize().getHeight()));
187 p_CropSpinnersPanel.setAlignmentX(LEFT_ALIGNMENT);
188 p_ControlPanelLeft.add(p_CropSpinnersPanel);
189 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 5)));
190 p_ControlPanelLeft.add(b_IMG_UpdateCropParams);
191 p_ControlPanelLeft.add(cbthsl.createJLabel("––––––––––––––––––", 1));
192 p_CBTHSettingsPanel.setMaximumSize(new Dimension(Short.MAX_VALUE,
193 (int) p_CBTHSettingsPanel.getMinimumSize().getHeight()));
194 p_CBTHSettingsPanel.setAlignmentX(LEFT_ALIGNMENT);
195 p_ControlPanelLeft.add(p_CBTHSettingsPanel);
196 p_ControlPanelLeft.add(cbthsl.createJLabel("––––––––––––––––––", 1));
197 p_ControlPanelLeft.add(b_IMG_ColorCalibration);
198 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 5)));

Pagina 308 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel1Img

199 p_ControlPanelLeft.add(b_IMG_ColorEstimation);
200 p_ControlPanelLeft.add(Box.createVerticalGlue()); // Fill blank space
201
202 this.add(sp_split, BorderLayout.CENTER);
203 }
204
205 // Getters:
206 public CBTHImage getImgCombo() {
207 return (CBTHImage) cb_ImageDropDown.getSelectedItem();
208 }
209
210 public CBTHImage getImgTemporary() {
211 return imgTemporary;
212 }
213
214 public JSpinner getS_IMG_Height() {
215 return s_IMG_Height;
216 }
217
218 public JSpinner getS_IMG_Width() {
219 return s_IMG_Width;
220 }
221
222 public JSpinner getS_IMG_X_CO() {
223 return s_IMG_X_CO;
224 }
225
226 public JSpinner getS_IMG_Y_CO() {
227 return s_IMG_Y_CO;
228 }
229
230 // Instance methods:
231 /**
232 * This method is part of the Observer-Observable technique. It gets triggered
233 * when the CBTHImagesList wants to. (Normally when changes occur.) Will
234 * update the combobox or images-dropdownlist, when new CBTHImages appear/get
235 * deleted.
236 */
237 public void update(Observable arg0, Object arg1) {
238 cb_ImageDropDown.removeAllItems();
239
240 int i, k = imgl.getSize();
241
242 for (i = 0; i < k; i++) {
243 cb_ImageDropDown.addItem(imgl.getCBTHImage(i));
244 }
245
246 /*
247 * After an update, the dropdown will show the most recent Image. "i-1" is
248 * needed because the
249 */
250 if (k > 0) {
251 cb_ImageDropDown.setSelectedItem(imgl.getCBTHImage(i - 1));
252 }
253 }
254
255 /**
256 * Is used to update the cropspinners with newly selected image from the
257 * dropdown. When an image was deleted, this method is also invoked.
258 */
259 public void updateImgCropSpinners(CBTHImage img) {
260
261 imgTemporary = img;
262
263 // Remove the listeners of the spinners:
264 try {

Pagina 309 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel1Img

265 s_IMG_X_CO.removeChangeListener(cropSpin);
266 } catch (NullPointerException npe) {
267 }
268 try {
269 s_IMG_Y_CO.removeChangeListener(cropSpin);
270 } catch (NullPointerException npe) {
271 }
272 try {
273 s_IMG_Width.removeChangeListener(cropSpin);
274 } catch (NullPointerException npe) {
275 }
276 try {
277 s_IMG_Height.removeChangeListener(cropSpin);
278 } catch (NullPointerException npe) {
279 }
280
281 // Create a new S_IMG_CropSpinnersListener:
282 cropSpin = new S_IMG_CropSpinnersListener(this, img, s_IMG_X_CO, s_IMG_Y_CO,
283 s_IMG_Width, s_IMG_Height);
284
285 if (img != null) {
286 s_IMG_X_CO.setModel(new SpinnerNumberModel(img.getCroppedXPos(), 0,
287 img.getWidthOriginal(), 1));
288 s_IMG_Y_CO.setModel(new SpinnerNumberModel(img.getCroppedYPos(), 0,
289 img.getHeightOriginal(), 1));
290 s_IMG_Width.setModel(new SpinnerNumberModel(img.getCroppedWidth(), 1,
291 img.getWidthOriginal(), 1));
292 s_IMG_Height.setModel(new SpinnerNumberModel(img.getCroppedHeight(), 1,
293 img.getHeightOriginal(), 1));
294 // Width & height have to be >= 1.
295
296 updateImgWindow(img);
297 }
298
299 else {
300 s_IMG_X_CO.setModel(new SpinnerNumberModel(0, 0, 100, 1));
301 s_IMG_Y_CO.setModel(new SpinnerNumberModel(0, 0, 100, 1));
302 s_IMG_Width.setModel(new SpinnerNumberModel(1, 1, 100, 1));
303 s_IMG_Height.setModel(new SpinnerNumberModel(1, 1, 100, 1));
304 }
305
306 s_IMG_X_CO.addChangeListener(cropSpin);
307 s_IMG_Y_CO.addChangeListener(cropSpin);
308 s_IMG_Width.addChangeListener(cropSpin);
309 s_IMG_Height.addChangeListener(cropSpin);
310
311 p_CropSpinnersPanel.repaint();
312 p_CropSpinnersPanel.revalidate();
313
314 /*
315 * Not necessary: this.repaint(); this.revalidate();
316 */
317 }
318
319 /**
320 * This method is responsible for the refreshment of the (cropped) image on
321 * the p_WindowPanelRight.
322 */
323 public void updateImgWindow(CBTHImage img) {
324
325 // Old content of p_WindowPanelRight is removed:
326 p_WindowPanelRight.removeAll();
327 p_WindowPanelRight.repaint();
328 p_WindowPanelRight.revalidate();
329
330 // New content is added:

Pagina 310 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel1Img

331 ScrollImageJPanel imgWindow = null;


332 BufferedImage bi = null;
333
334 // Check whether the cropped image can be updated:
335 if (img != null) {
336 bi = img.getImgCropped();
337 }
338
339 imgWindow = new ScrollImageJPanel(bi);
340
341 p_WindowPanelRight.add(imgWindow, BorderLayout.CENTER);
342 this.repaint();
343 this.revalidate();
344 }
345
346 // Static method:
347 public static JSpinner createCropSpinner(String toolTipText) {
348
349 JSpinner cropSpinner = new JSpinner();
350 cropSpinner.setFont(guiFont1);
351 cropSpinner.setToolTipText(toolTipText);
352
353 int breedteSp = cropSpinner.getMaximumSize().width;
354 int hoogteSp = cropSpinner.getMinimumSize().height;
355 cropSpinner.setMaximumSize(new Dimension(breedteSp, hoogteSp));
356
357 return cropSpinner;
358 }
359 }

Pagina 311 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel2Cub

1 package view;
2
3 import java.awt.*;
4 import javax.swing.*;
5 import java.util.Observable;
6 import java.util.Observer;
7
8 import listeners.cube.*;
9 import model.*;
10
11 public class ViewTabPanel2Cub extends JPanel implements Observer {
12
13 private static final long serialVersionUID = 1L;
14 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
15 private JSplitPane sp_split1;
16 private JSplitPane sp_split2;
17
18 private JPanel p_ControlPanelLeft;
19 private JPanel p_CubeFacePanelUp;
20 private JPanel p_CubeFacePanelDown;
21 private JPanel p_RotateAndNavigatePanel;
22
23 private JButton b_CUBE_AssignToMainCubeFace;
24 private JButton b_CUBE_DeleteCubeFace;
25 private JButton b_CUBE_RotateCubeFaceLeft;
26 private JButton b_CUBE_RotateCubeFaceRight;
27 private JButton b_CUBE_NavigateNextCubeFace;
28 private JButton b_CUBE_NavigatePreviousCubeFace;
29 private JButton b_CUBE_BuildVirtualCube;
30
31 private JComboBox<CubeFace> cb_MainCubeFacesCombo;
32 private CubeFace[] mainCubeFacesArray;
33 private VisualCubeFace[] visualMainCubeFaces;
34 private CubeFace currentCubeFace;
35 private CubeFacesList cfl;
36
37 // Constructor:
38 public ViewTabPanel2Cub(CubeFacesList cfl) {
39 super(new BorderLayout());
40
41 Font guiFont1 = cbthsl.getFont("guiFont1");
42
43 // Create JComponents:
44 p_ControlPanelLeft = new JPanel();
45 p_ControlPanelLeft
46 .setLayout(new BoxLayout(p_ControlPanelLeft, BoxLayout.PAGE_AXIS));
47
48 p_CubeFacePanelUp = new JPanel();
49 p_CubeFacePanelDown = new JPanel();
50
51 this.cfl = cfl;
52 currentCubeFace = null;
53
54 mainCubeFacesArray = cfl.getAllMainCubeFaces();
55 visualMainCubeFaces = new VisualCubeFace[mainCubeFacesArray.length];
56 for (int i = 0; i < mainCubeFacesArray.length; i++) {
57 visualMainCubeFaces[i] = mainCubeFacesArray[i].createVCubeFace();
58 }
59
60 cb_MainCubeFacesCombo = new JComboBox<CubeFace>(mainCubeFacesArray);
61 cb_MainCubeFacesCombo.setFont(guiFont1);
62 Co_CUBE_MainCFacesDropdownListener mcfdl = new Co_CUBE_MainCFacesDropdownListener(
63 this);
64 cb_MainCubeFacesCombo.addItemListener(mcfdl);
65
66 // Create JButtons:

Pagina 312 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel2Cub

67 b_CUBE_AssignToMainCubeFace = cbthsl.createJButton(
68 "Assign cubeface \u2191",
69 "Will assign the cubeface from below to the selected maincubeface.",
70 new B_CUBE_AssignToMainCubeFaceListener(this));
71 b_CUBE_BuildVirtualCube = cbthsl.createJButton("Build virtual cube",
72 "Will build a virtual cube according to the maincubefaces.",
73 new B_CUBE_BuildVirtualCubeListener(cfl));
74 b_CUBE_DeleteCubeFace = cbthsl.createJButton("Delete cubeface",
75 "Will remove the selected cubeface from the list below.",
76 new B_CUBE_DeleteCubeFaceListener(this, cfl));
77 b_CUBE_RotateCubeFaceLeft = cbthsl.createJButton("\u21BA",
78 "Will rotate the current cubeface 90° counterclockwise.",
79 new B_CUBE_TurnCFace90Degrees(this, false));
80 b_CUBE_RotateCubeFaceRight = cbthsl.createJButton("\u21BB",
81 "Will rotate the current cubeface 90° counterclockwise.",
82 new B_CUBE_TurnCFace90Degrees(this, true));
83
84 b_CUBE_RotateCubeFaceLeft
85 .setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20));
86 b_CUBE_RotateCubeFaceRight
87 .setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20));
88
89 String[] iconPathCompNextButton = { "img", "icon", "Play-icon.png" };
90 String[] iconPathCompPreviousButton = { "img", "icon",
91 "ReversePlay-icon.png" };
92
93 b_CUBE_NavigatePreviousCubeFace = cbthsl.createJButton(null,
94 "Navigates to the previous cubeface in the list.",
95 new B_CUBE_PreviousCubeFaceListener(this, cfl));
96 b_CUBE_NavigatePreviousCubeFace.setIcon(new ImageIcon(
97 cbthsl.makeSysIndepFilePath(iconPathCompPreviousButton, 2)));
98
99 b_CUBE_NavigateNextCubeFace = cbthsl.createJButton(null,
100 "Navigates to the next cubeface in the list.",
101 new B_CUBE_NextCubeFaceListener(this, cfl));
102 b_CUBE_NavigateNextCubeFace.setIcon(
103 new ImageIcon(cbthsl.makeSysIndepFilePath(iconPathCompNextButton, 2)));
104
105 // Assembling the p_ControlPanelLeft:
106 cb_MainCubeFacesCombo.setAlignmentX(LEFT_ALIGNMENT);
107 cb_MainCubeFacesCombo
108 .setMaximumSize(cb_MainCubeFacesCombo.getMinimumSize());
109 p_ControlPanelLeft.add(cb_MainCubeFacesCombo);
110 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
111 p_ControlPanelLeft.add(b_CUBE_AssignToMainCubeFace);
112 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
113 p_ControlPanelLeft.add(b_CUBE_DeleteCubeFace);
114 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
115
116 p_RotateAndNavigatePanel = new JPanel(new GridLayout(2, 2));
117 p_RotateAndNavigatePanel.add(b_CUBE_RotateCubeFaceLeft);
118 p_RotateAndNavigatePanel.add(b_CUBE_RotateCubeFaceRight);
119 p_RotateAndNavigatePanel.add(b_CUBE_NavigatePreviousCubeFace);
120 p_RotateAndNavigatePanel.add(b_CUBE_NavigateNextCubeFace);
121
122 Dimension d = p_RotateAndNavigatePanel.getMinimumSize();
123 Dimension e = p_RotateAndNavigatePanel.getMaximumSize();
124
125 p_RotateAndNavigatePanel.setMaximumSize(new Dimension(e.width, d.height));
126 p_RotateAndNavigatePanel.setAlignmentX(LEFT_ALIGNMENT);
127 p_ControlPanelLeft.add(p_RotateAndNavigatePanel);
128 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
129
130 p_ControlPanelLeft.add(b_CUBE_BuildVirtualCube);
131
132 // Making a vertical JSplitPane for the CubeFaces-array's.

Pagina 313 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel2Cub

133 sp_split2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT,


134 new JScrollPane(p_CubeFacePanelUp),
135 new JScrollPane(p_CubeFacePanelDown));
136 sp_split2.setDividerLocation(200);
137
138 // Making a horizontal JSplitPane between p_ControlPanelLeft and sp_split2.
139 sp_split1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
140 new JScrollPane(p_ControlPanelLeft,
141 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
142 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
143 sp_split2);
144 sp_split1.setDividerLocation(280);
145
146 this.add(sp_split1, BorderLayout.CENTER);
147
148 // By default, the LeftFace is selected:
149 cubeFacePanelUpUpdate(mainCubeFacesArray[0]);
150 }
151
152 // Getters:
153 public CubeFace getCurrentCubeFace() {
154 return currentCubeFace;
155 }
156
157 public CubeFace getSelectedMainCubeFaceFromCombo() {
158 return (CubeFace) cb_MainCubeFacesCombo.getSelectedItem();
159 }
160
161 // Setter:
162 public void setCurrentCubeFace(CubeFace cf) {
163 currentCubeFace = cf;
164 cubeFacePanelDownUpdate();
165 }
166
167 // Instance methods:
168 /**
169 * Will show the currentCubeFace in the p_CubeFacePanelDown.
170 */
171 public void cubeFacePanelDownUpdate() {
172
173 // Delete old content p_CubeFacePanelDown:
174 p_CubeFacePanelDown.removeAll();
175
176 if (currentCubeFace != null) {
177 // Getting is VisualCubeFace rather than creating a new one.
178 p_CubeFacePanelDown.add(currentCubeFace.getVisualCubeFace());
179 }
180
181 // Show new content:
182 p_CubeFacePanelDown.repaint();
183 p_CubeFacePanelDown.revalidate();
184 }
185
186 /**
187 * Will update the p_CubeFacePanelUp with the specified CubeFace as parameter.
188 *
189 * @param cf
190 * The CubeFace that needs to be shown.
191 */
192 public void cubeFacePanelUpUpdate(CubeFace cf) {
193
194 // Delete old content p_CubeFacePanelUp:
195 p_CubeFacePanelUp.removeAll();
196 p_CubeFacePanelUp.repaint();
197 p_CubeFacePanelUp.revalidate();
198

Pagina 314 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel2Cub

199 if (cf != null) {


200
201 // Getting is VisualCubeFace rather than creating a new one.
202 boolean foundYet = false;
203 int i = 0;
204 while (i < mainCubeFacesArray.length && !foundYet) {
205 if (mainCubeFacesArray[i] == cf) {
206 foundYet = true;
207 } else {
208 i++;
209 }
210 }
211 p_CubeFacePanelUp.add(visualMainCubeFaces[i]);
212 }
213
214 // Show new content:
215 p_CubeFacePanelUp.repaint();
216 p_CubeFacePanelUp.revalidate();
217 }
218
219 /**
220 * This method is part of the Observer-Observable technique. It gets triggered
221 * when the CubeFacesList wants to. (Normally when changes occur.) In the body
222 * is referred to cubeFacePanelDownUpdate();
223 */
224 public void update(Observable arg0, Object arg1) {
225
226 if (cfl.getSize() > 0) {
227 // '-1' to avoid ArrayIndexOutOfBoundsException
228 CubeFace cf = cfl.getCubeFace(cfl.getSize() - 1);
229 setCurrentCubeFace(cf);
230 } else {
231 setCurrentCubeFace(null);
232 }
233 cubeFacePanelDownUpdate();
234 }
235 }

Pagina 315 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel3Sol

1 package view;
2
3 import java.awt.BorderLayout;
4 import java.awt.Dimension;
5 import java.awt.FlowLayout;
6
7 import javax.swing.*;
8
9 import exceptions.NoSuchSettingFoundException;
10 import listeners.solv.*;
11 import model.CBTHSettingsList;
12 import model.CommonObjects;
13
14 public class ViewTabPanel3Sol extends JPanel {
15
16 private static final long serialVersionUID = 1L;
17 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
18
19 private JSplitPane split;
20 private JPanel p_ControlPanelLeft;
21 private JPanel p_WindowPanelRight;
22 private JPanel p_OneSettingPanel;
23
24 private JButton b_SOLV_CubeToSolver;
25 private JButton b_SOLV_SolutionToRobot;
26 private JButton b_SOLV_EnumerateMoves;
27 private JButton b_SOLV_BlenderGUI;
28
29 private VisualCBTHSetting vcbthsUpdateVisWithRobot;
30
31 // Constructor:
32 public ViewTabPanel3Sol() {
33
34 super(new BorderLayout());
35
36 // Create JComponents:
37 p_ControlPanelLeft = new JPanel();
38 p_ControlPanelLeft
39 .setLayout(new BoxLayout(p_ControlPanelLeft, BoxLayout.PAGE_AXIS));
40
41 b_SOLV_CubeToSolver = cbthsl.createJButton("Cube \u2192 solver",
42 "Virtual cube will be loaded to the solver.",
43 CommonObjects.getCubeToSolver());
44 b_SOLV_SolutionToRobot = cbthsl.createJButton("Solution \u2192 robot",
45 "Will add the solution to the robot's instruction-queue.",
46 CommonObjects.getMoveSeqToRobot());
47 b_SOLV_EnumerateMoves = cbthsl.createJButton(
48 "Enumerate solution-commands.",
49 "This function will print out the solution commands if calculated.",
50 new B_SOLV_EnumerateMovesListener());
51 b_SOLV_BlenderGUI = cbthsl.createJButton("BlenderGUI",
52 "Will show a visualization upon Cubie's internal cube representation.",
53 new B_SOLV_BlenderGUIListener());
54
55 String[] iconPathComp = { "img", "icon", "Blender-icon22x23.png" };
56 b_SOLV_BlenderGUI
57 .setIcon(new ImageIcon(cbthsl.makeSysIndepFilePath(iconPathComp, 2)));
58
59 try {
60 vcbthsUpdateVisWithRobot = cbthsl
61 .seekCBTHSetting("updateVisualizationWithRobot").createVCBTHSetting();
62
63 } catch (NoSuchSettingFoundException nssfe) {
64 System.err.println(nssfe);
65 }
66

Pagina 316 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel3Sol

67 p_OneSettingPanel = new JPanel();


68
69 if (vcbthsUpdateVisWithRobot != null) {
70
71 p_OneSettingPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
72 p_OneSettingPanel.add(vcbthsUpdateVisWithRobot.getL_CBTHSLabel());
73 p_OneSettingPanel.add(vcbthsUpdateVisWithRobot.getTF_CBTHSValue());
74 }
75
76 // Assembling the p_ControlPanelLeft:
77 p_ControlPanelLeft.add(b_SOLV_CubeToSolver);
78 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
79 p_ControlPanelLeft.add(b_SOLV_SolutionToRobot);
80 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
81 p_ControlPanelLeft.add(b_SOLV_EnumerateMoves);
82 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
83 p_ControlPanelLeft.add(b_SOLV_BlenderGUI);
84 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
85 p_ControlPanelLeft.add(p_OneSettingPanel);
86 p_OneSettingPanel.setAlignmentX(LEFT_ALIGNMENT);
87 p_ControlPanelLeft.add(Box.createVerticalGlue()); // Fill blank space
88
89 p_WindowPanelRight = CommonObjects.getCubie();
90
91 // Making a horizontal JSplitPane between p_ControlPanelLeft and
92 // p_WindowPanelRight.
93 split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
94 new JScrollPane(p_ControlPanelLeft,
95 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
96 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
97 new JScrollPane(p_WindowPanelRight));
98 split.setDividerLocation(280);
99
100 this.add(split, BorderLayout.CENTER);
101 }
102 }

Pagina 317 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel4Aut

1 package view;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
5 import java.awt.Dimension;
6 import java.awt.GridLayout;
7 import javax.swing.*;
8
9 import exceptions.NoSuchSettingFoundException;
10 import model.*;
11 import listeners.aut.*;
12
13 public class ViewTabPanel4Aut extends JPanel {
14
15 private static final long serialVersionUID = 1L;
16 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
17 private static String[][] textSubTasks = {
18 { "[1] Read cube", "[2] Build virtual cube", "[3] Solve algorithmic",
19 "[4] Send solution" },
20 { "Dient aangevinkt te worden indien automatische werking de kubus nog moet inlezen.",
21 "Dient aangevinkt te worden indien de virtuele kubus nog moet worden opgebouwd tijdens
22 automatische werking.",
23 "Dient aangevinkt te worden indien de solver van Jaap Scherphuis de oplossing nog moet
24 berekenen.",
25 "Dient te worden aangevinkt als men de Robot wil aansturen met oplossings commando's." } };
26
27 private JSplitPane sp_split;
28 private JPanel p_ControlPanelLeft;
29 private JPanel p_WindowPanelRight;
30
31 private JToggleButton[] toggleIncludeTasks;
32 private JButton b_AUT_CommandToRobot;
33 private JButton b_AUT_AutomaticRoutine;
34 private JButton b_AUT_StopAutoRoutine;
35
36 private ViewTabSubPanelAut[] vtspa;
37
38 private JLabel l_IncludeTasks;
39
40 private JTextArea ta_CubeConfig;
41 private JTextArea ta_CommandsToRobot;
42
43 // Constructor:
44 public ViewTabPanel4Aut(CBTHImagesList imgl, CubeFacesList cfl) {
45
46 super(new BorderLayout());
47
48 // Create JComponents:
49 p_ControlPanelLeft = new JPanel();
50 p_ControlPanelLeft
51 .setLayout(new BoxLayout(p_ControlPanelLeft, BoxLayout.PAGE_AXIS));
52
53 toggleIncludeTasks = new JToggleButton[4];
54 for (int i = 0; i < toggleIncludeTasks.length; i++) {
55 toggleIncludeTasks[i] = cbthsl.createJToggleButton(textSubTasks[0][i],
56 textSubTasks[1][i], true);
57 toggleIncludeTasks[i].addItemListener(new T_AUT_SubTasksItemListener(i));
58 }
59
60 b_AUT_AutomaticRoutine = cbthsl.createJButton("Automatic routine",
61 "Will perform the one-click automatic routine.",
62 new B_AUT_AutomaticRoutineListener(imgl, cfl, this));
63 b_AUT_StopAutoRoutine = cbthsl.createJButton("Stop auto. routine",
64 "Will stop the automatic procedure as quickly as possible.",
65 new B_AUT_StopAutoRoutineListener());
66 b_AUT_CommandToRobot = cbthsl.createJButton("Command \u2192 robot",

Pagina 318 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel4Aut

67 "Will add a command to the robot's instruction queue.",


68 new B_AUT_CommandToRobotListener());
69 l_IncludeTasks = cbthsl.createJLabel("Include subtasks:", 1);
70
71 // Add intuitive backgroundcolors.
72 b_AUT_AutomaticRoutine.setBackground(Color.GREEN);
73 b_AUT_StopAutoRoutine.setBackground(Color.RED);
74
75 // Assembling the p_ControlPanelLeft:
76 p_ControlPanelLeft.add(l_IncludeTasks);
77 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 5)));
78 for (int j = 0; j < toggleIncludeTasks.length; j++) {
79 p_ControlPanelLeft.add(toggleIncludeTasks[j]);
80 }
81 p_ControlPanelLeft.add(new JLabel("––––––––––––––––––"));
82 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 5)));
83 p_ControlPanelLeft.add(b_AUT_AutomaticRoutine);
84 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 10)));
85 p_ControlPanelLeft.add(b_AUT_StopAutoRoutine);
86 p_ControlPanelLeft.add(new JLabel("––––––––––––––––––"));
87 p_ControlPanelLeft.add(Box.createRigidArea(new Dimension(0, 5)));
88 p_ControlPanelLeft.add(b_AUT_CommandToRobot);
89
90 p_WindowPanelRight = new JPanel();
91 p_WindowPanelRight
92 .setLayout(new BoxLayout(p_WindowPanelRight, BoxLayout.PAGE_AXIS));
93
94 vtspa = new ViewTabSubPanelAut[textSubTasks[0].length];
95 JPanel contentPanels[] = new JPanel[textSubTasks[0].length];
96 contentPanels[0] = makeReadingCubeSubPanel();
97 contentPanels[1] = makeVirtualCubeSubPanel();
98 contentPanels[2] = makeSolveAlgorithmicSubPanel();
99 contentPanels[3] = makeSendSolutionSubPanel();
100
101 for (int i = 0; i < textSubTasks[0].length; i++) {
102 // ContentPanels are wrapped in ViewTabSubPanelAut's.
103 vtspa[i] = new ViewTabSubPanelAut(textSubTasks[0][i], false,
104 contentPanels[i]);
105 p_WindowPanelRight.add(vtspa[i]);
106 p_WindowPanelRight.add(Box.createRigidArea(new Dimension(0, 5)));
107 }
108 p_WindowPanelRight.add(Box.createVerticalGlue());
109
110 // Making a horizontal JSplitPane between p_ControlPanelLeft and
111 // p_WindowPanelRight.
112 sp_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
113 new JScrollPane(p_ControlPanelLeft,
114 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
115 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
116 new JScrollPane(p_WindowPanelRight,
117 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
118 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED));
119 sp_split.setDividerLocation(280);
120
121 add(sp_split, BorderLayout.CENTER);
122 }
123
124 // Instance methods:
125 // Making subpanels that are displayed in the p_WindowPanelRight:
126 public JPanel makeReadingCubeSubPanel() {
127
128 // Initializing components:
129 JPanel panel = new JPanel();
130
131 /*
132 * The idea is to make two columns, on the left-handside we get the

Pagina 319 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel4Aut

133 * labeltexts from the CBTHSetting, while the right column will provide a
134 * sync-ing JTextField.
135 */
136 panel.setLayout(new GridLayout(0, 2, 15, 5));
137
138 String[][] cbthSettingsToBeListed = {
139 { "captureDevice", "xCoCrop", "yCoCrop", "widthCrop", "heightCrop" },
140 { "amountOfSamplesPerFacelet", "amountOfSampleAveraging",
141 "thresholdColorEstimation", "extensiveSampleOutprint" },
142 { "cubeReadingToppleArray", "cubeReadingMCFRotationArray",
143 "cubeReadingMCFAssignArray" } };
144 JLabel[] interjectionLabels = {
145 cbthsl.createJLabel("––––––––––––––––––", 1),
146 cbthsl.createJLabel("WARNING! ADVANCED SETTINGS:", 3) };
147
148 for (int i = 0; i < cbthSettingsToBeListed.length; i++) {
149 addSettingsToSubPanel(panel, cbthSettingsToBeListed[i]);
150 if (i < cbthSettingsToBeListed.length - 1) {
151 panel.add(interjectionLabels[i]);
152 panel.add(new JPanel());
153 }
154 }
155 return panel;
156 }
157
158 public JPanel makeSendSolutionSubPanel() {
159 JPanel panel = new JPanel(new BorderLayout());
160 ta_CommandsToRobot = new JTextArea(7, 20);
161 ta_CommandsToRobot.setEditable(false);
162 ta_CommandsToRobot.setFont(cbthsl.getFont("guiFont2"));
163 String newLine = cbthsl.getString("newLine");
164 ta_CommandsToRobot.setText(newLine + newLine
165 + "<Solution sequence will be displayed here, once available.>");
166
167 panel.add(
168 new JScrollPane(ta_CommandsToRobot,
169 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
170 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS),
171 BorderLayout.CENTER);
172 return panel;
173 }
174
175 public JPanel makeSolveAlgorithmicSubPanel() {
176 JPanel panel = new JPanel();
177 panel.setLayout(new GridLayout(0, 2, 15, 5));
178
179 String[] cbthSettingsToBeListed = { "timeToSolveAlgorithm" };
180
181 addSettingsToSubPanel(panel, cbthSettingsToBeListed);
182
183 return panel;
184 }
185
186 public JPanel makeVirtualCubeSubPanel() {
187 JPanel panel = new JPanel(new BorderLayout());
188 ta_CubeConfig = new JTextArea(7, 20);
189 ta_CubeConfig.setEditable(false);
190 ta_CubeConfig.setFont(cbthsl.getFont("guiFont2"));
191 String newLine = cbthsl.getString("newLine");
192 ta_CubeConfig.setText(newLine + newLine
193 + "<Virtual cube will be displayed here, once available.>");
194
195 panel.add(
196 new JScrollPane(ta_CubeConfig,
197 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
198 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS),

Pagina 320 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabPanel4Aut

199 BorderLayout.CENTER);
200 return panel;
201 }
202
203 /**
204 * Controls the green Logo's on the ViewTabSubpanelAut's: whether they should
205 * highlight or not.
206 *
207 * @param indexSubtask
208 * Which subtask needs to be highlighted.
209 * @param onOff
210 * To toggle the logo on/off.
211 */
212 public void setLogoOnOffVtspa(int indexSubtask, boolean onOff) {
213 vtspa[indexSubtask].setOnOff(onOff);
214 }
215
216 /** Will update the solution textArea on the tab [AUTOMATIC MODE] */
217 public void updateSendSolutionSubPanel() {
218 ta_CommandsToRobot.setText(CommandSeq.solutionCommandsMatrixToString());
219 }
220
221 /** Will update the virtual cube textArea on the tab [AUTOMATIC MODE] */
222 public void updateVirtCubeSubPanel() {
223 ta_CubeConfig.setText(CubeConfiguration.cubeConfigPrint());
224 }
225
226 // Static method:
227 /**
228 * This method will add CBTHSettings to some JPanel
229 *
230 * @param panel
231 * The JPanel where the settings need te
232 * @param cbthSettingsToBeListed
233 * Array of Strings with CBTHSetting-names.
234 */
235 public static void addSettingsToSubPanel(JPanel panel,
236 String[] cbthSettingsToBeListed) {
237 CBTHSetting cbths = null;
238 VisualCBTHSetting viscbths = null;
239
240 for (int j = 0; j < cbthSettingsToBeListed.length; j++) {
241 try {
242 cbths = cbthsl.seekCBTHSetting(cbthSettingsToBeListed[j]);
243 viscbths = cbths.createVCBTHSetting();
244
245 panel.add(viscbths.getL_CBTHSLabel());
246 panel.add(viscbths.getTF_CBTHSValue());
247
248 } catch (NoSuchSettingFoundException nssfe) {
249 System.err.println(nssfe);
250 }
251 }
252 }
253 }

Pagina 321 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabSubPanelAut

1 package view;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
5 import javax.swing.*;
6
7 import model.CBTHSettingsList;
8 import model.CommonObjects;
9
10 public class ViewTabSubPanelAut extends JPanel {
11
12 private static final long serialVersionUID = 1L;
13 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
14 private static String[] iconPathCompON = { "img", "icon",
15 "WDLogo30x30ON.png" };
16 private static String[] iconPathCompOFF = { "img", "icon",
17 "WDLogo30x30OFF.png" };
18 private static String iconPathON = cbthsl.makeSysIndepFilePath(iconPathCompON,
19 2);
20 private static String iconPathOFF = cbthsl
21 .makeSysIndepFilePath(iconPathCompOFF, 2);
22 private static final ImageIcon cbthIconON = new ImageIcon(iconPathON);
23 private static final ImageIcon cbthIconOFF = new ImageIcon(iconPathOFF);
24
25 private JLabel titleLabel;
26 private String title;
27 private JPanel content;
28 private BorderLayout borderLayout;
29
30 // Constructor:
31 public ViewTabSubPanelAut(String title, boolean active, JPanel content) {
32
33 this.title = title;
34 this.titleLabel = cbthsl.createJLabel(this.title, 1);
35 titleLabel.setForeground(Color.GREEN);
36 titleLabel.setBackground(new Color(60, 30, 6));
37 titleLabel.setOpaque(true);
38
39 if (active) {
40 titleLabel.setIcon(cbthIconON);
41 } else {
42 titleLabel.setIcon(cbthIconOFF);
43 }
44
45 this.content = content;
46
47 this.borderLayout = new BorderLayout();
48 this.setLayout(borderLayout);
49
50 this.add(titleLabel, BorderLayout.PAGE_START);
51 if (content != null) {
52 this.add(this.content, BorderLayout.CENTER);
53 }
54 }
55
56 // Setters:
57 /**
58 * Sets content-panel.
59 *
60 * @param newContent
61 * A JPanel is passed.
62 */
63 public void setContent(JPanel newContent) {
64 this.content = newContent;
65
66 this.revalidate();

Pagina 322 van 329 CubeThesis™ Depamelaere-Deschuytter


class ViewTabSubPanelAut

67 this.repaint();
68 }
69
70 /**
71 * Will put logo on/off
72 *
73 * @param onOff
74 * Boolean On = true
75 */
76 public void setOnOff(boolean onOff) {
77
78 if (onOff) {
79 titleLabel.setIcon(cbthIconON);
80 } else {
81 titleLabel.setIcon(cbthIconOFF);
82 }
83 this.revalidate();
84 this.repaint();
85 }
86 }

Pagina 323 van 329 CubeThesis™ Depamelaere-Deschuytter


class VisualCBTHSetting

1 package view;
2
3 import java.util.Observable;
4 import java.util.Observer;
5 import javax.swing.*;
6
7 import listeners.cbthsettings.TF_VisualCBTHSettingListener;
8 import model.CBTHSetting;
9 import model.CBTHSettingsList;
10 import model.CommonObjects;
11
12 public class VisualCBTHSetting implements Observer {
13
14 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
15 private CBTHSetting cbths;
16 private JTextField tf_CBTHSValue;
17 private JLabel l_CBTHSLabel;
18
19 // Constructors:
20 public VisualCBTHSetting() {
21 super();
22 this.cbths = null;
23 }
24
25 public VisualCBTHSetting(CBTHSetting cbths) {
26 super();
27 this.cbths = cbths;
28
29 this.tf_CBTHSValue = cbthsl.createJTextField(cbths.getValue(),
30 cbths.getEditable(), cbths.getInfo());
31
32 if (cbths.getEditable()) {
33 // ActionListener/DocumentListener is added to register updates from user.
34 tf_CBTHSValue
35 .addActionListener(new TF_VisualCBTHSettingListener(cbths, this));
36 }
37
38 this.l_CBTHSLabel = cbthsl.createJLabel(cbths.getLabelText(), 1);
39 this.l_CBTHSLabel.setToolTipText(cbths.getName());
40 }
41
42 // Getters:
43 public JLabel getL_CBTHSLabel() {
44 return l_CBTHSLabel;
45 }
46
47 public JTextField getTF_CBTHSValue() {
48 return tf_CBTHSValue;
49 }
50
51 // Instance method:
52 /**
53 * This method is part of the Observer-Observable technique. It gets triggered
54 * when the CBTHSetting wants to. (Normally when changes occur.)
55 */
56 public void update(Observable arg0, Object arg1) {
57
58 // Optional: To also refresh the label, each time the value changes.
59 /*
60 * l_CBTHSLabel.setText(cbths.getLabelText()); l_CBTHSLabel.repaint();
61 */
62
63 tf_CBTHSValue.setText(cbths.getValue());
64 tf_CBTHSValue.setToolTipText(cbths.getInfo());
65 }
66 }

Pagina 324 van 329 CubeThesis™ Depamelaere-Deschuytter


class VisualCBTHSettingsCustomizer

1 package view;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Dimension;
6 import java.awt.GridLayout;
7 import java.util.ArrayList;
8 import java.util.Observable;
9 import java.util.Observer;
10 import javax.swing.*;
11
12 import listeners.cbthsettings.TF_SettingsCustomizerDocumentListener;
13 import model.CommonObjects;
14 import model.CBTHSetting;
15 import model.CBTHSettingsList;
16
17 public class VisualCBTHSettingsCustomizer extends JPanel implements Observer {
18
19 private static final long serialVersionUID = 1L;
20 private CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
21 private JPanel p_CBTHSettingSelection;
22
23 private JTextField tf_DynamicSearchBar;
24 private JScrollPane sp_ScrollPane;
25
26 // Constructor:
27 public VisualCBTHSettingsCustomizer() {
28
29 super(new BorderLayout());
30
31 p_CBTHSettingSelection = new JPanel();
32 p_CBTHSettingSelection
33 .setLayout(new BoxLayout(p_CBTHSettingSelection, BoxLayout.PAGE_AXIS));
34
35 // Listen for changes in the text
36 String s_DynamicFilterBar =
37 "Dynamic filterbar: Specify fragment of CBTHSetting's [name] "
38 + "or [labeltext] to filter.";
39 tf_DynamicSearchBar = cbthsl.createJTextField(s_DynamicFilterBar, true,
40 s_DynamicFilterBar);
41 tf_DynamicSearchBar.getDocument().addDocumentListener(
42 new TF_SettingsCustomizerDocumentListener(tf_DynamicSearchBar));
43 tf_DynamicSearchBar.selectAll();
44
45 sp_ScrollPane = new JScrollPane(p_CBTHSettingSelection,
46 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
47 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
48 sp_ScrollPane.setMaximumSize(sp_ScrollPane.getMinimumSize());
49
50 update(null, null);
51
52 this.add(tf_DynamicSearchBar, BorderLayout.PAGE_START);
53
54 sp_ScrollPane.setPreferredSize(new Dimension(500, 400));
55
56 this.add(sp_ScrollPane, BorderLayout.CENTER);
57 this.add(new JLabel(), BorderLayout.PAGE_END);
58
59 this.repaint();
60 }
61
62 // Instance method:
63 /**
64 * This method is part of the Observer-Observable technique. It gets triggered
65 * when the CBTHSettingsList wants to. (Normally when changes occur, here when
66 * a new fragment is filtered.)

Pagina 325 van 329 CubeThesis™ Depamelaere-Deschuytter


class VisualCBTHSettingsCustomizer

67 */
68 public void update(Observable arg0, Object arg1) {
69
70 p_CBTHSettingSelection.removeAll();
71
72 ArrayList<CBTHSetting> arrayListSelection = cbthsl
73 .getCBTHSettingSelection();
74 VisualCBTHSetting vcbths;
75
76 for (CBTHSetting cbths : arrayListSelection) {
77
78 JPanel p_OneSettingPanel = new JPanel(new GridLayout(0, 2, 20, 0));
79 p_OneSettingPanel.setMaximumSize(new Dimension(Short.MAX_VALUE,
80 (int) p_OneSettingPanel.getMinimumSize().getHeight()));
81 vcbths = cbths.createVCBTHSetting();
82
83 vcbths.getL_CBTHSLabel().setAlignmentX(Component.LEFT_ALIGNMENT);
84 p_OneSettingPanel.add(vcbths.getL_CBTHSLabel());
85
86 vcbths.getTF_CBTHSValue().setAlignmentX(Component.LEFT_ALIGNMENT);
87 p_OneSettingPanel.add(vcbths.getTF_CBTHSValue());
88
89 p_CBTHSettingSelection.add(p_OneSettingPanel);
90 p_CBTHSettingSelection.add(Box.createRigidArea(new Dimension(0, 5)));
91 }
92
93 // Create stretchable blank space:
94 p_CBTHSettingSelection.add(Box.createVerticalGlue());
95
96 sp_ScrollPane.setViewportView(p_CBTHSettingSelection);
97 sp_ScrollPane.repaint();
98 }
99 }

Pagina 326 van 329 CubeThesis™ Depamelaere-Deschuytter


class VisualCubeFace

1 package view;
2
3 import java.awt.Color;
4 import java.awt.Font;
5 import java.awt.GridLayout;
6 import java.util.Observable;
7 import java.util.Observer;
8 import javax.swing.*;
9
10 import listeners.cube.Co_CUBE_ColorsOnCubeFaceDropdownListener;
11 import model.CBTHSettingsList;
12 import model.CommonObjects;
13 import model.CubeFace;
14
15 public class VisualCubeFace extends JPanel implements Observer {
16
17 private static final long serialVersionUID = 1L;
18 private static CBTHSettingsList cbthsl = CommonObjects.getCBTHSettingsList();
19 private static String[] kubusKleuren = cbthsl.getCubeColors();
20 private static Font guiFont1 = cbthsl.getFont("guiFont1");
21 private CubeFace cf;
22 private JComboBox[][] comboBoxMatrix;
23 private Co_CUBE_ColorsOnCubeFaceDropdownListener[][] dropdownListenerMatrix;
24 private JLabel[][] labelMatrix;
25
26 // Constructor:
27 public VisualCubeFace(CubeFace cf) {
28
29 super();
30 this.cf = cf;
31
32 this.setLayout(new GridLayout(3, 6));
33
34 comboBoxMatrix = new JComboBox[3][3];
35 JComboBox<String> comBox = null;
36 dropdownListenerMatrix = new Co_CUBE_ColorsOnCubeFaceDropdownListener[3][3];
37
38 labelMatrix = new JLabel[3][3];
39 JLabel label = null;
40
41 for (int r = 0; r < comboBoxMatrix.length; r++) {
42
43 for (int s = 0; s < comboBoxMatrix[0].length; s++) {
44
45 // Prepare 3 colums of comboboxes:
46 comBox = new JComboBox<String>(kubusKleuren);
47 comBox.setEditable(false);
48 comBox.setSelectedItem(cbthsl.translateColorsIntToString(6));
49 comBox.setFont(guiFont1);
50 comBox.setMaximumSize(comBox.getMinimumSize());
51
52 dropdownListenerMatrix[r][s] = new Co_CUBE_ColorsOnCubeFaceDropdownListener(
53 cf, r, s);
54 comBox.addItemListener(dropdownListenerMatrix[r][s]);
55
56 comboBoxMatrix[r][s] = comBox;
57 this.add(comBox);
58 comBox = null;
59 }
60
61 for (int t = 0; t < labelMatrix[0].length; t++) {
62
63 // Prepare 3 columns of labels.
64 label = cbthsl.createJLabel("0.0%", 1);
65 label.setOpaque(true);
66 label.setMaximumSize(label.getMinimumSize());

Pagina 327 van 329 CubeThesis™ Depamelaere-Deschuytter


class VisualCubeFace

67
68 labelMatrix[r][t] = label;
69 this.add(label);
70 }
71 }
72 }
73
74 // Instance methods:
75 public void comboboxesActive(boolean active) {
76
77 for (int i = 0; i < comboBoxMatrix.length; i++) {
78 for (int j = 0; j < comboBoxMatrix[0].length; j++) {
79 dropdownListenerMatrix[i][j].setActive(active);
80 }
81 }
82 }
83
84 /**
85 * This method is part of the Observer-Observable technique. It gets triggered
86 * when the CubeFace wants to. (Normally when changes occur.)
87 */
88 public void update(Observable arg0, Object arg1) {
89
90 int[][] colorsMatrix = cf.getColorsMatrix();
91 double[][] confidencesMatrix = cf.getConfidenceMatrix();
92
93 double thresholdColorEstimation = cbthsl
94 .getDouble("thresholdColorEstimation");
95
96 if (colorsMatrix != null) {
97 JLabel labelTemp = null;
98 /*
99 * Avoid them updating all the time while refreshing. There's a problem
100 * that the listeners applied to the comboBoxes trigger all the time when
101 * the combo- BoxMatrix[][] gets its new items in this method. To save all
102 * the extra effort, they're made inactive.
103 */
104 comboboxesActive(false);
105
106 for (int r = 0; r < colorsMatrix.length; r++) {
107 for (int s = 0; s < colorsMatrix[0].length; s++) {
108 comboBoxMatrix[r][s]
109 .setSelectedItem(kubusKleuren[(colorsMatrix[r][s])]);
110 }
111 }
112 comboboxesActive(true);
113
114 for (int r = 0; r < colorsMatrix.length; r++) {
115 for (int t = 0; t < confidencesMatrix[0].length; t++) {
116
117 labelTemp = labelMatrix[r][t];
118 labelTemp.setText(confidencesMatrix[r][t] + "%");
119
120 if (confidencesMatrix[r][t] == 100) {
121 labelTemp.setBackground(Color.GREEN);
122 labelTemp.setForeground(Color.BLACK);
123 } else {
124 if (confidencesMatrix[r][t] > thresholdColorEstimation
125 && confidencesMatrix[r][t] < 100) {
126 // Certaintylevel is above threshold but less than 100%.
127 labelTemp.setBackground(new Color(255, 140, 0));// Orange
128 labelTemp.setForeground(Color.BLACK);
129 } else {
130 // Certaintylevel is below threshold.
131 labelTemp.setBackground(Color.RED);
132 labelTemp.setForeground(Color.WHITE);

Pagina 328 van 329 CubeThesis™ Depamelaere-Deschuytter


class VisualCubeFace

133 }
134 }
135 }
136 }
137 // This lines below have been added to make sure the panel updates within
138 // the pop-up window.
139 this.revalidate();
140 this.repaint();
141 }
142 }
143 }

Pagina 329 van 329 CubeThesis™ Depamelaere-Deschuytter

You might also like