Project

General

Profile

Download (15.3 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / screens / RubikScreenSolver.java @ c9f72ca3

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.screens;
11

    
12
import static org.distorted.objectlib.main.TwistyObject.*;
13

    
14
import java.lang.ref.WeakReference;
15

    
16
import android.content.SharedPreferences;
17
import android.graphics.Bitmap;
18
import android.graphics.Canvas;
19
import android.graphics.Paint;
20
import android.graphics.PorterDuff;
21
import android.graphics.drawable.Drawable;
22
import android.os.Bundle;
23
import androidx.core.content.ContextCompat;
24
import android.view.View;
25
import android.widget.ImageButton;
26
import android.widget.LinearLayout;
27

    
28
import org.distorted.dialogs.RubikDialogSolverImpossible;
29
import org.distorted.main.MainActivity;
30
import org.distorted.objectlib.main.ObjectControl;
31
import org.distorted.objectlib.signature.ObjectConstants;
32
import org.distorted.objectlib.main.TwistyObject;
33

    
34
import org.distorted.dialogs.RubikDialogSolverError;
35
import org.distorted.helpers.TransparentImageButton;
36
import org.distorted.main.R;
37
import org.distorted.main_old.RubikActivity;
38
import org.distorted.objectlib.shape.ShapeDiamond;
39
import org.distorted.objectlib.shape.ShapeDodecahedron;
40
import org.distorted.objectlib.shape.ShapeHexahedron;
41
import org.distorted.objectlib.shape.ShapeIcosahedron;
42
import org.distorted.objectlib.shape.ShapeOctahedron;
43
import org.distorted.objectlib.shape.ShapeTetrahedron;
44
import org.distorted.objects.RubikObjectList;
45
import org.distorted.solvers.ImplementedSolversList;
46
import org.distorted.solvers.SolverMain;
47

    
48
///////////////////////////////////////////////////////////////////////////////////////////////////
49

    
50
public class RubikScreenSolver extends RubikScreenAbstract
51
  {
52
  private static final int RESET_DURATION = 1000;
53
  private static final int MODE_NORMAL = 0;
54
  private static final int MODE_DINO_4 = 1;
55

    
56
  private static Bitmap[] mBitmap;
57
  private ImageButton[] mColorButton;
58
  private TransparentImageButton mResetButton,mBackButton, mSolveButton;
59
  private boolean mSolving;
60
  private int mCurrentColor, mCurrentButton;
61
  private int[] mFaceColors;
62
  private int mColorMode;
63
  private int mNumColors;
64
  private float mBitmapSize;
65
  private WeakReference<RubikActivity> mWeakAct;
66

    
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68

    
69
  void leaveScreen(RubikActivity act)
70
    {
71
    ObjectControl control = act.getControl();
72
    control.unsetLock();
73
    }
74

    
75
///////////////////////////////////////////////////////////////////////////////////////////////////
76

    
77
  void enterScreen(final RubikActivity act)
78
    {
79
    ObjectControl control = act.getControl();
80
    control.setLock(false);
81

    
82
    float width = act.getScreenWidthInPixels();
83
    float heigh = act.getScreenHeightInPixels();
84

    
85
    mWeakAct = new WeakReference<>(act);
86
    mSolving = false;
87

    
88
    int solverIndex= act.getSolverIndex();
89
    ImplementedSolversList currentSolver = ImplementedSolversList.getSolver(solverIndex);
90
    int currentObject = currentSolver.getObject();
91
    act.changeIfDifferent(currentObject,control);
92
    control.solveOnly();
93
    RubikObjectList.setCurrObject(currentObject);
94

    
95
    generateFaceColors(currentObject);
96

    
97
    final float BUTTON_RATIO = 0.75f;
98
    int sizeV = (int)(heigh*MainActivity.RATIO_BAR*BUTTON_RATIO);
99
    int sizeH = (int)((width/mNumColors)*BUTTON_RATIO);
100
    mBitmapSize = Math.min(sizeV,sizeH);
101

    
102
    // TOP ////////////////////////////
103
    LinearLayout layoutTop = act.findViewById(R.id.upperBar);
104
    layoutTop.removeAllViews();
105

    
106
    if( mNumColors>0 )
107
      {
108
      setupBitmaps();
109
      setupColorButtons(act,width);
110
      markButton(act);
111
      }
112

    
113
    for(ImageButton button: mColorButton) layoutTop.addView(button);
114

    
115
    // BOT ////////////////////////////
116
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1);
117

    
118
    LinearLayout layoutL = new LinearLayout(act);
119
    layoutL.setLayoutParams(params);
120
    LinearLayout layoutM = new LinearLayout(act);
121
    layoutM.setLayoutParams(params);
122
    LinearLayout layoutR = new LinearLayout(act);
123
    layoutR.setLayoutParams(params);
124

    
125
    LinearLayout layoutBot = act.findViewById(R.id.lowerBar);
126
    layoutBot.removeAllViews();
127

    
128
    setupResetButton(act);
129
    setupSolveButton(act);
130
    setupBackButton(act);
131

    
132
    layoutL.addView(mResetButton);
133
    layoutM.addView(mSolveButton);
134
    layoutR.addView(mBackButton);
135

    
136
    layoutBot.addView(layoutL);
137
    layoutBot.addView(layoutM);
138
    layoutBot.addView(layoutR);
139
    }
140

    
141
///////////////////////////////////////////////////////////////////////////////////////////////////
142
// This doesn't quite work in many cases, but in case of the solvers that will pop up in foreseeable
143
// future it should be ok.
144

    
145
  public void generateFaceColors(int object)
146
    {
147
    mColorMode = MODE_NORMAL;
148

    
149
    if( object== ObjectConstants.PYRA_3 ||
150
        object== ObjectConstants.PYRA_4 ||
151
        object== ObjectConstants.PYRA_5 ||
152
        object== ObjectConstants.PDUO_2 ||
153
        object== ObjectConstants.JING_2 ||
154
        object== ObjectConstants.MORP_2 ||
155
        object== ObjectConstants.MORP_3 ||
156
        object== ObjectConstants.MORP_4  )
157
      {
158
      mNumColors  = ShapeTetrahedron.NUM_FACES;
159
      mFaceColors = ShapeTetrahedron.FACE_COLORS;
160
      }
161
    else if( object== ObjectConstants.DIAM_2 ||
162
             object== ObjectConstants.DIAM_3 ||
163
             object== ObjectConstants.DIAM_4 ||
164
             object== ObjectConstants.TRAJ_3 ||
165
             object== ObjectConstants.TRAJ_4 ||
166
             object== ObjectConstants.PDIA_3  )
167
      {
168
      mNumColors  = ShapeOctahedron.NUM_FACES;
169
      mFaceColors = ShapeOctahedron.FACE_COLORS;
170
      }
171
    else if( object== ObjectConstants.CRYS_3 ||
172
             object== ObjectConstants.STAR_3 ||
173
             object== ObjectConstants.PENT_2 ||
174
             object== ObjectConstants.KILO_3 ||
175
             object== ObjectConstants.KILO_5 ||
176
             object== ObjectConstants.MEGA_3 ||
177
             object== ObjectConstants.MEGA_5  )
178
      {
179
      mNumColors  = ShapeDodecahedron.NUM_FACES;
180
      mFaceColors = ShapeDodecahedron.FACE_COLORS;
181
      }
182
    else if( object== ObjectConstants.BALL_4 )
183
      {
184
      mNumColors  = ShapeDiamond.NUM_FACES;
185
      mFaceColors = ShapeDiamond.FACE_COLORS;
186
      }
187
    else if( object== ObjectConstants.ICOS_2 )
188
      {
189
      mNumColors  = ShapeIcosahedron.NUM_FACES;
190
      mFaceColors = ShapeIcosahedron.FACE_COLORS;
191
      }
192
    else if( object== ObjectConstants.DIN4_3 )
193
      {
194
      mNumColors  = 4;
195
      mFaceColors = new int[] { COLOR_YELLOW, COLOR_RED, COLOR_BLUE, COLOR_WHITE };
196
      mColorMode  = MODE_DINO_4;
197
      }
198
    else
199
      {
200
      mNumColors  = ShapeHexahedron.NUM_FACES;
201
      mFaceColors = ShapeHexahedron.FACE_COLORS;
202
      }
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

    
207
  private void setupBitmaps()
208
    {
209
    final int SIZE = (int)mBitmapSize;
210
    final float R = SIZE*0.15f;
211
    final float M = SIZE*0.08f;
212

    
213
    mBitmap = new Bitmap[mNumColors];
214

    
215
    Paint paint = new Paint();
216
    paint.setColor(0xff008800);
217
    paint.setStyle(Paint.Style.FILL);
218

    
219
    paint.setAntiAlias(true);
220
    paint.setTextAlign(Paint.Align.CENTER);
221
    paint.setStyle(Paint.Style.FILL);
222

    
223
    for(int i=0; i<mNumColors; i++)
224
      {
225
      mBitmap[i] = Bitmap.createBitmap(SIZE, SIZE, Bitmap.Config.ARGB_8888);
226
      Canvas canvas = new Canvas(mBitmap[i]);
227

    
228
      paint.setColor(0xff000000);
229
      canvas.drawRect(0, 0, SIZE, SIZE, paint);
230

    
231
      paint.setColor(mFaceColors[i]);
232
      canvas.drawRoundRect( M, M, SIZE-M, SIZE-M, R, R, paint);
233
      }
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237

    
238
  private int translateColor(int color)
239
    {
240
    if( mColorMode==MODE_DINO_4 )
241
      {
242
      int realColor = mFaceColors[color];
243
      int[] hexColors = ShapeHexahedron.FACE_COLORS;
244

    
245
      for(int i=0; i<6; i++)
246
        if( hexColors[i]==realColor ) return i;
247
      }
248

    
249
    return color;
250
    }
251

    
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253

    
254
  private void setupColorButtons(final RubikActivity act, final float width)
255
    {
256
    mColorButton = new ImageButton[mNumColors];
257
    int padding = (int)(width*RubikActivity.PADDING);
258
    int margin  = (int)(width*RubikActivity.SMALL_MARGIN);
259

    
260
    for(int i=0; i<mNumColors; i++)
261
      {
262
      final int ii = i;
263
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.MATCH_PARENT, 1.0f);
264
      params.topMargin    = margin;
265
      params.bottomMargin = margin;
266
      params.leftMargin   = margin;
267
      params.rightMargin  = margin;
268

    
269
      mColorButton[i] = new ImageButton(act);
270
      mColorButton[i].setLayoutParams(params);
271
      mColorButton[i].setPadding(padding,0,padding,0);
272
      mColorButton[i].setImageBitmap(mBitmap[i]);
273

    
274
      mColorButton[i].setOnClickListener( new View.OnClickListener()
275
        {
276
        @Override
277
        public void onClick(View view)
278
          {
279
          mCurrentColor = translateColor(ii);
280
          mCurrentButton= ii;
281
          markButton(act);
282
          }
283
        });
284
      }
285
    }
286

    
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288

    
289
  private void setupResetButton(final RubikActivity act)
290
    {
291
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
292
    mResetButton = new TransparentImageButton(act, R.drawable.ui_reset, params);
293

    
294
    mResetButton.setOnClickListener( new View.OnClickListener()
295
      {
296
      @Override
297
      public void onClick(View v)
298
        {
299
        ObjectControl control = act.getControl();
300
        control.resetTextureMapsEffect(RESET_DURATION);
301
        }
302
      });
303
    }
304

    
305
///////////////////////////////////////////////////////////////////////////////////////////////////
306

    
307
  private void setupSolveButton(final RubikActivity act)
308
    {
309
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
310
    mSolveButton = new TransparentImageButton(act,R.drawable.ui_solve,params);
311

    
312
    mSolveButton.setOnClickListener( new View.OnClickListener()
313
      {
314
      @Override
315
      public void onClick(View v)
316
        {
317
        if( !mSolving )
318
          {
319
          mSolving = true;
320
          TwistyObject object = act.getObject();
321
          SolverMain solver = new SolverMain( act.getInterface(), act.getResources(), object );
322
          solver.start();
323
          }
324
        }
325
      });
326
    }
327

    
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329

    
330
  private void setupBackButton(final RubikActivity act)
331
    {
332
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
333
    mBackButton = new TransparentImageButton(act,R.drawable.ui_back,params);
334

    
335
    mBackButton.setOnClickListener( new View.OnClickListener()
336
      {
337
      @Override
338
      public void onClick(View v)
339
        {
340
        ObjectControl control = act.getControl();
341
        control.resetAllTextureMaps();
342
        ScreenList.goBack(act);
343
        }
344
      });
345
    }
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

    
349
  private void markButton(RubikActivity act)
350
    {
351
    if( mCurrentButton>=mNumColors )
352
      {
353
      mCurrentButton = 0;
354
      mCurrentColor = translateColor(0);
355
      }
356

    
357
    for(int b=0; b<mNumColors; b++)
358
      {
359
      Drawable d = mColorButton[b].getBackground();
360

    
361
      if( b==mCurrentButton )
362
        {
363
        d.setColorFilter(ContextCompat.getColor(act,R.color.red), PorterDuff.Mode.MULTIPLY);
364
        }
365
      else
366
        {
367
        d.clearColorFilter();
368
        }
369
      }
370
    }
371

    
372
///////////////////////////////////////////////////////////////////////////////////////////////////
373

    
374
  public void savePreferences(SharedPreferences.Editor editor)
375
    {
376
    editor.putInt("stateSolver_color" , mCurrentColor );
377
    editor.putInt("stateSolver_button", mCurrentButton);
378
    }
379

    
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381

    
382
  public void restorePreferences(SharedPreferences preferences)
383
    {
384
    mCurrentColor = preferences.getInt("stateSolver_color" , 0);
385
    mCurrentButton= preferences.getInt("stateSolver_button", 0);
386
    }
387

    
388
///////////////////////////////////////////////////////////////////////////////////////////////////
389

    
390
  public int getCurrentColor()
391
    {
392
    return mCurrentColor;
393
    }
394

    
395
///////////////////////////////////////////////////////////////////////////////////////////////////
396

    
397
  public void setSolved(final String moves)
398
    {
399
    mSolving = false;
400
    final RubikActivity act = mWeakAct.get();
401

    
402
    if( act!=null )
403
      {
404
      act.runOnUiThread(new Runnable()
405
        {
406
        @Override
407
        public void run()
408
          {
409
          ScreenList.switchScreen(act, ScreenList.SOLU);
410
          RubikScreenSolution solution = (RubikScreenSolution) ScreenList.SOLU.getScreenClass();
411
          solution.setupMoves(act, moves);
412
          }
413
        });
414
      }
415
    }
416

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418

    
419
  public void setSolved(final int[][] moves)
420
    {
421
    mSolving = false;
422
    final RubikActivity act = mWeakAct.get();
423

    
424
    if( act!=null )
425
      {
426
      act.runOnUiThread(new Runnable()
427
        {
428
        @Override
429
        public void run()
430
          {
431
          ScreenList.switchScreen(act, ScreenList.SOLU);
432
          RubikScreenSolution solution = (RubikScreenSolution) ScreenList.SOLU.getScreenClass();
433
          solution.setupMoves(act, moves);
434
          }
435
        });
436
      }
437
    }
438

    
439
///////////////////////////////////////////////////////////////////////////////////////////////////
440

    
441
  public void displayErrorDialog(String message)
442
    {
443
    mSolving = false;
444
    RubikActivity act = mWeakAct.get();
445

    
446
    if( act!=null )
447
      {
448
      RubikDialogSolverError dialog = new RubikDialogSolverError();
449
      Bundle bundle = new Bundle();
450
      bundle.putString("argument", message );
451
      dialog.setArguments(bundle);
452
      dialog.show( act.getSupportFragmentManager(), null);
453
      }
454
    }
455

    
456
///////////////////////////////////////////////////////////////////////////////////////////////////
457

    
458
  public void displayImpossibleDialog(String message)
459
    {
460
    mSolving = false;
461
    RubikActivity act = mWeakAct.get();
462

    
463
    if( act!=null )
464
      {
465
      RubikDialogSolverImpossible dialog = new RubikDialogSolverImpossible();
466
      Bundle bundle = new Bundle();
467
      bundle.putString("argument", message );
468
      dialog.setArguments(bundle);
469
      dialog.show( act.getSupportFragmentManager(), null);
470
      }
471
    }
472
  }
(8-8/10)