Project

General

Profile

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

magiccube / src / main / java / org / distorted / screens / RubikScreenSolver.java @ 244cc23f

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.objectlib.main.ObjectControl;
30
import org.distorted.objectlib.signature.ObjectConstants;
31
import org.distorted.objectlib.main.TwistyObject;
32

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

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

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

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

    
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

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

    
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75

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

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

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

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

    
94
    generateFaceColors(currentObject);
95

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

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

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

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

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

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

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

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

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

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

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

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

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

    
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

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

    
212
    mBitmap = new Bitmap[mNumColors];
213

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

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

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

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

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

    
235
///////////////////////////////////////////////////////////////////////////////////////////////////
236

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

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

    
248
    return color;
249
    }
250

    
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252

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

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

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

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

    
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287

    
288
  private void setupResetButton(final RubikActivity act)
289
    {
290
    int icon = RubikActivity.getDrawable(R.drawable.ui_small_reset,R.drawable.ui_medium_reset, R.drawable.ui_big_reset, R.drawable.ui_huge_reset);
291
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
292
    mResetButton = new TransparentImageButton(act, icon, TransparentImageButton.GRAVITY_MIDDLE, 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
    final int icon = RubikActivity.getDrawable(R.drawable.ui_small_solve,R.drawable.ui_medium_solve, R.drawable.ui_big_solve, R.drawable.ui_huge_solve);
310
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
311
    mSolveButton = new TransparentImageButton(act,icon,TransparentImageButton.GRAVITY_MIDDLE,params);
312

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

    
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330

    
331
  private void setupBackButton(final RubikActivity act)
332
    {
333
    final int icon = RubikActivity.getDrawable(R.drawable.ui_small_back,R.drawable.ui_medium_back, R.drawable.ui_big_back, R.drawable.ui_huge_back);
334
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
335
    mBackButton = new TransparentImageButton(act, icon, TransparentImageButton.GRAVITY_MIDDLE, params);
336

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

    
349
///////////////////////////////////////////////////////////////////////////////////////////////////
350

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

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

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

    
374
///////////////////////////////////////////////////////////////////////////////////////////////////
375

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

    
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383

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

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391

    
392
  public int getCurrentColor()
393
    {
394
    return mCurrentColor;
395
    }
396

    
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398

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

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

    
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420

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

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

    
441
///////////////////////////////////////////////////////////////////////////////////////////////////
442

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

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

    
458
///////////////////////////////////////////////////////////////////////////////////////////////////
459

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

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