Project

General

Profile

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

magiccube / src / main / java / org / distorted / solverui / ScreenSolver.java @ 62054004

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 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.solverui;
11

    
12
import static org.distorted.objectlib.main.TwistyObject.COLOR_BLUE;
13
import static org.distorted.objectlib.main.TwistyObject.COLOR_RED;
14
import static org.distorted.objectlib.main.TwistyObject.COLOR_WHITE;
15
import static org.distorted.objectlib.main.TwistyObject.COLOR_YELLOW;
16

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

    
28
import androidx.core.content.ContextCompat;
29

    
30
import org.distorted.dialogs.RubikDialogSolverError;
31
import org.distorted.dialogs.RubikDialogSolverImpossible;
32
import org.distorted.helpers.TransparentImageButton;
33
import org.distorted.main.MainActivity;
34
import org.distorted.main.R;
35
import org.distorted.objectlib.main.ObjectControl;
36
import org.distorted.objectlib.main.TwistyObject;
37
import org.distorted.objectlib.metadata.MetadataBALL_4;
38
import org.distorted.objectlib.metadata.MetadataCRYS_3;
39
import org.distorted.objectlib.metadata.MetadataDIAM_2;
40
import org.distorted.objectlib.metadata.MetadataDIAM_3;
41
import org.distorted.objectlib.metadata.MetadataDIAM_4;
42
import org.distorted.objectlib.metadata.MetadataDIN4_3;
43
import org.distorted.objectlib.metadata.MetadataICOS_2;
44
import org.distorted.objectlib.metadata.MetadataJING_2;
45
import org.distorted.objectlib.metadata.MetadataKILO_3;
46
import org.distorted.objectlib.metadata.MetadataKILO_5;
47
import org.distorted.objectlib.metadata.MetadataMEGA_3;
48
import org.distorted.objectlib.metadata.MetadataMEGA_5;
49
import org.distorted.objectlib.metadata.MetadataMORP_2;
50
import org.distorted.objectlib.metadata.MetadataMORP_3;
51
import org.distorted.objectlib.metadata.MetadataMORP_4;
52
import org.distorted.objectlib.metadata.MetadataPDIA_3;
53
import org.distorted.objectlib.metadata.MetadataPDUO_2;
54
import org.distorted.objectlib.metadata.MetadataPENT_2;
55
import org.distorted.objectlib.metadata.MetadataPYRA_3;
56
import org.distorted.objectlib.metadata.MetadataPYRA_4;
57
import org.distorted.objectlib.metadata.MetadataPYRA_5;
58
import org.distorted.objectlib.metadata.MetadataSTAR_3;
59
import org.distorted.objectlib.metadata.MetadataTRAJ_3;
60
import org.distorted.objectlib.metadata.MetadataTRAJ_4;
61
import org.distorted.objectlib.shape.ShapeDiamond;
62
import org.distorted.objectlib.shape.ShapeDodecahedron;
63
import org.distorted.objectlib.shape.ShapeHexahedron;
64
import org.distorted.objectlib.shape.ShapeIcosahedron;
65
import org.distorted.objectlib.shape.ShapeOctahedron;
66
import org.distorted.objectlib.shape.ShapeTetrahedron;
67
import org.distorted.solvers.ImplementedSolversList;
68
import org.distorted.solvers.SolverMain;
69

    
70
import java.lang.ref.WeakReference;
71

    
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73

    
74
public class ScreenSolver extends ScreenAbstract
75
  {
76
  private static final int RESET_DURATION = 1000;
77
  private static final int MODE_NORMAL = 0;
78
  private static final int MODE_DINO_4 = 1;
79

    
80
  private static Bitmap[] mBitmap;
81
  private ImageButton[] mColorButton;
82
  private TransparentImageButton mResetButton,mBackButton, mSolveButton;
83
  private boolean mSolving;
84
  private int mCurrentColor, mCurrentButton;
85
  private int[] mFaceColors;
86
  private int mColorMode;
87
  private int mNumColors;
88
  private float mBitmapSize;
89
  private WeakReference<SolverActivity> mWeakAct;
90

    
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92

    
93
  void leaveScreen(SolverActivity act)
94
    {
95
    ObjectControl control = act.getControl();
96
    control.unsetLock();
97
    }
98

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100

    
101
  void enterScreen(final SolverActivity act)
102
    {
103
    ObjectControl control = act.getControl();
104
    control.setLock(false);
105

    
106
    float width = act.getScreenWidthInPixels();
107
    float heigh = act.getScreenHeightInPixels();
108

    
109
    mWeakAct = new WeakReference<>(act);
110
    mSolving = false;
111

    
112
    int solverIndex= act.getSolverOrdinal();
113
    ImplementedSolversList currentSolver = ImplementedSolversList.getSolver(solverIndex);
114
    int currentObject = currentSolver.getObject();
115
    control.solveOnly();
116
    generateFaceColors(currentObject);
117

    
118
    final float BUTTON_RATIO = 0.75f;
119
    int sizeV = (int)(heigh*MainActivity.RATIO_BAR*BUTTON_RATIO);
120
    int sizeH = (int)((width/mNumColors)*BUTTON_RATIO);
121
    mBitmapSize = Math.min(sizeV,sizeH);
122

    
123
    // TOP ////////////////////////////
124
    LinearLayout layoutTop = act.findViewById(R.id.upperBar);
125
    layoutTop.removeAllViews();
126

    
127
    if( mNumColors>0 )
128
      {
129
      setupBitmaps();
130
      setupColorButtons(act,width);
131
      markButton(act);
132
      }
133

    
134
    for(ImageButton button: mColorButton) layoutTop.addView(button);
135

    
136
    // BOT ////////////////////////////
137
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1);
138

    
139
    LinearLayout layoutL = new LinearLayout(act);
140
    layoutL.setLayoutParams(params);
141
    LinearLayout layoutM = new LinearLayout(act);
142
    layoutM.setLayoutParams(params);
143
    LinearLayout layoutR = new LinearLayout(act);
144
    layoutR.setLayoutParams(params);
145

    
146
    LinearLayout layoutBot = act.findViewById(R.id.lowerBar);
147
    layoutBot.removeAllViews();
148

    
149
    setupResetButton(act);
150
    setupSolveButton(act);
151
    setupBackButton(act);
152

    
153
    layoutL.addView(mResetButton);
154
    layoutM.addView(mSolveButton);
155
    layoutR.addView(mBackButton);
156

    
157
    layoutBot.addView(layoutL);
158
    layoutBot.addView(layoutM);
159
    layoutBot.addView(layoutR);
160
    }
161

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163
// This doesn't quite work in many cases, but in case of the solvers that will pop up in foreseeable
164
// future it should be ok.
165

    
166
  public void generateFaceColors(int object)
167
    {
168
    mColorMode = MODE_NORMAL;
169

    
170
    if( object==MetadataPYRA_3.INDEX ||
171
        object==MetadataPYRA_4.INDEX ||
172
        object==MetadataPYRA_5.INDEX ||
173
        object==MetadataPDUO_2.INDEX ||
174
        object==MetadataJING_2.INDEX ||
175
        object==MetadataMORP_2.INDEX ||
176
        object==MetadataMORP_3.INDEX ||
177
        object==MetadataMORP_4.INDEX  )
178
      {
179
      mNumColors  = ShapeTetrahedron.NUM_FACES;
180
      mFaceColors = ShapeTetrahedron.FACE_COLORS;
181
      }
182
    else if( object==MetadataDIAM_2.INDEX ||
183
             object==MetadataDIAM_3.INDEX ||
184
             object==MetadataDIAM_4.INDEX ||
185
             object==MetadataTRAJ_3.INDEX ||
186
             object==MetadataTRAJ_4.INDEX ||
187
             object==MetadataPDIA_3.INDEX  )
188
      {
189
      mNumColors  = ShapeOctahedron.NUM_FACES;
190
      mFaceColors = ShapeOctahedron.FACE_COLORS;
191
      }
192
    else if( object==MetadataCRYS_3.INDEX ||
193
             object==MetadataSTAR_3.INDEX ||
194
             object==MetadataPENT_2.INDEX ||
195
             object==MetadataKILO_3.INDEX ||
196
             object==MetadataKILO_5.INDEX ||
197
             object==MetadataMEGA_3.INDEX ||
198
             object==MetadataMEGA_5.INDEX  )
199
      {
200
      mNumColors  = ShapeDodecahedron.NUM_FACES;
201
      mFaceColors = ShapeDodecahedron.FACE_COLORS;
202
      }
203
    else if( object==MetadataBALL_4.INDEX )
204
      {
205
      mNumColors  = ShapeDiamond.NUM_FACES;
206
      mFaceColors = ShapeDiamond.FACE_COLORS;
207
      }
208
    else if( object==MetadataICOS_2.INDEX )
209
      {
210
      mNumColors  = ShapeIcosahedron.NUM_FACES;
211
      mFaceColors = ShapeIcosahedron.FACE_COLORS;
212
      }
213
    else if( object==MetadataDIN4_3.INDEX )
214
      {
215
      mNumColors  = 4;
216
      mFaceColors = new int[] { COLOR_YELLOW, COLOR_RED, COLOR_BLUE, COLOR_WHITE };
217
      mColorMode  = MODE_DINO_4;
218
      }
219
    else
220
      {
221
      mNumColors  = ShapeHexahedron.NUM_FACES;
222
      mFaceColors = ShapeHexahedron.FACE_COLORS;
223
      }
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  private void setupBitmaps()
229
    {
230
    final int SIZE = (int)mBitmapSize;
231
    final float R = SIZE*0.15f;
232
    final float M = SIZE*0.08f;
233

    
234
    mBitmap = new Bitmap[mNumColors];
235

    
236
    Paint paint = new Paint();
237
    paint.setColor(0xff008800);
238
    paint.setStyle(Paint.Style.FILL);
239

    
240
    paint.setAntiAlias(true);
241
    paint.setTextAlign(Paint.Align.CENTER);
242
    paint.setStyle(Paint.Style.FILL);
243

    
244
    for(int i=0; i<mNumColors; i++)
245
      {
246
      mBitmap[i] = Bitmap.createBitmap(SIZE, SIZE, Bitmap.Config.ARGB_8888);
247
      Canvas canvas = new Canvas(mBitmap[i]);
248

    
249
      paint.setColor(0xff000000);
250
      canvas.drawRect(0, 0, SIZE, SIZE, paint);
251

    
252
      paint.setColor(mFaceColors[i]);
253
      canvas.drawRoundRect( M, M, SIZE-M, SIZE-M, R, R, paint);
254
      }
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  private int translateColor(int color)
260
    {
261
    if( mColorMode==MODE_DINO_4 )
262
      {
263
      int realColor = mFaceColors[color];
264
      int[] hexColors = ShapeHexahedron.FACE_COLORS;
265

    
266
      for(int i=0; i<6; i++)
267
        if( hexColors[i]==realColor ) return i;
268
      }
269

    
270
    return color;
271
    }
272

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

    
275
  private void setupColorButtons(final SolverActivity act, final float width)
276
    {
277
    mColorButton = new ImageButton[mNumColors];
278
    int padding = (int)(width*SolverActivity.PADDING);
279
    int margin  = (int)(width*SolverActivity.SMALL_MARGIN);
280

    
281
    for(int i=0; i<mNumColors; i++)
282
      {
283
      final int ii = i;
284
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.MATCH_PARENT, 1.0f);
285
      params.topMargin    = margin;
286
      params.bottomMargin = margin;
287
      params.leftMargin   = margin;
288
      params.rightMargin  = margin;
289

    
290
      mColorButton[i] = new ImageButton(act);
291
      mColorButton[i].setLayoutParams(params);
292
      mColorButton[i].setPadding(padding,0,padding,0);
293
      mColorButton[i].setImageBitmap(mBitmap[i]);
294

    
295
      mColorButton[i].setOnClickListener( new View.OnClickListener()
296
        {
297
        @Override
298
        public void onClick(View view)
299
          {
300
          mCurrentColor = translateColor(ii);
301
          mCurrentButton= ii;
302
          markButton(act);
303
          }
304
        });
305
      }
306
    }
307

    
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309

    
310
  private void setupResetButton(final SolverActivity act)
311
    {
312
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
313
    mResetButton = new TransparentImageButton(act, R.drawable.ui_reset, params);
314

    
315
    mResetButton.setOnClickListener( new View.OnClickListener()
316
      {
317
      @Override
318
      public void onClick(View v)
319
        {
320
        ObjectControl control = act.getControl();
321
        control.resetTextureMapsEffect(RESET_DURATION);
322
        }
323
      });
324
    }
325

    
326
///////////////////////////////////////////////////////////////////////////////////////////////////
327

    
328
  private void setupSolveButton(final SolverActivity act)
329
    {
330
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
331
    mSolveButton = new TransparentImageButton(act,R.drawable.ui_solve,params);
332

    
333
    mSolveButton.setOnClickListener( new View.OnClickListener()
334
      {
335
      @Override
336
      public void onClick(View v)
337
        {
338
        if( !mSolving )
339
          {
340
          mSolving = true;
341
          TwistyObject object = act.getObject();
342
          SolverMain solver = new SolverMain( act.getInterface(), act.getResources(), object );
343
          solver.start();
344
          }
345
        }
346
      });
347
    }
348

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

    
351
  private void setupBackButton(final SolverActivity act)
352
    {
353
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
354
    mBackButton = new TransparentImageButton(act,R.drawable.ui_back,params);
355

    
356
    mBackButton.setOnClickListener( new View.OnClickListener()
357
      {
358
      @Override
359
      public void onClick(View v)
360
        {
361
        ObjectControl control = act.getControl();
362
        control.resetAllTextureMaps();
363
        ScreenList.goBack(act);
364
        }
365
      });
366
    }
367

    
368
///////////////////////////////////////////////////////////////////////////////////////////////////
369

    
370
  private void markButton(SolverActivity act)
371
    {
372
    if( mCurrentButton>=mNumColors )
373
      {
374
      mCurrentButton = 0;
375
      mCurrentColor = translateColor(0);
376
      }
377

    
378
    for(int b=0; b<mNumColors; b++)
379
      {
380
      Drawable d = mColorButton[b].getBackground();
381

    
382
      if( b==mCurrentButton )
383
        {
384
        d.setColorFilter(ContextCompat.getColor(act,R.color.red), PorterDuff.Mode.MULTIPLY);
385
        }
386
      else
387
        {
388
        d.clearColorFilter();
389
        }
390
      }
391
    }
392

    
393
///////////////////////////////////////////////////////////////////////////////////////////////////
394

    
395
  public void savePreferences(SharedPreferences.Editor editor)
396
    {
397
    editor.putInt("stateSolver_color" , mCurrentColor );
398
    editor.putInt("stateSolver_button", mCurrentButton);
399
    }
400

    
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402

    
403
  public void restorePreferences(SharedPreferences preferences)
404
    {
405
    mCurrentColor = preferences.getInt("stateSolver_color" , 0);
406
    mCurrentButton= preferences.getInt("stateSolver_button", 0);
407
    }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

    
411
  public int getCurrentColor()
412
    {
413
    return mCurrentColor;
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  public void setSolved(final String moves)
419
    {
420
    mSolving = false;
421
    final SolverActivity act = mWeakAct.get();
422

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

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

    
440
  public void setSolved(final int[][] moves)
441
    {
442
    mSolving = false;
443
    final SolverActivity act = mWeakAct.get();
444

    
445
    if( act!=null )
446
      {
447
      act.runOnUiThread(new Runnable()
448
        {
449
        @Override
450
        public void run()
451
          {
452
          ScreenList.switchScreen(act, ScreenList.SOLU);
453
          ScreenSolution solution = (ScreenSolution) ScreenList.SOLU.getScreenClass();
454
          solution.setupMoves(act, moves);
455
          }
456
        });
457
      }
458
    }
459

    
460
///////////////////////////////////////////////////////////////////////////////////////////////////
461

    
462
  public void displayErrorDialog(String message)
463
    {
464
    mSolving = false;
465
    SolverActivity act = mWeakAct.get();
466

    
467
    if( act!=null )
468
      {
469
      RubikDialogSolverError dialog = new RubikDialogSolverError();
470
      Bundle bundle = new Bundle();
471
      bundle.putString("argument", message );
472
      dialog.setArguments(bundle);
473
      dialog.show( act.getSupportFragmentManager(), null);
474
      }
475
    }
476

    
477
///////////////////////////////////////////////////////////////////////////////////////////////////
478

    
479
  public void displayImpossibleDialog(String message)
480
    {
481
    mSolving = false;
482
    SolverActivity act = mWeakAct.get();
483

    
484
    if( act!=null )
485
      {
486
      RubikDialogSolverImpossible dialog = new RubikDialogSolverImpossible();
487
      Bundle bundle = new Bundle();
488
      bundle.putString("argument", message );
489
      dialog.setArguments(bundle);
490
      dialog.show( act.getSupportFragmentManager(), null);
491
      }
492
    }
493
  }
(4-4/8)