Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / ScreenSetupPosition.java @ dc56cfb6

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.solvers;
11

    
12
import android.content.SharedPreferences;
13
import android.graphics.Bitmap;
14
import android.graphics.Canvas;
15
import android.graphics.Paint;
16
import android.graphics.PorterDuff;
17
import android.graphics.drawable.Drawable;
18
import android.os.Bundle;
19
import android.view.View;
20
import android.widget.ImageButton;
21
import android.widget.LinearLayout;
22

    
23
import androidx.core.content.ContextCompat;
24
import androidx.fragment.app.FragmentManager;
25

    
26
import org.distorted.dialogs.DialogInterrupt;
27
import org.distorted.dialogs.DialogSolverError;
28
import org.distorted.dialogs.DialogSolverImpossible;
29
import org.distorted.dialogs.DialogSolvers;
30
import org.distorted.helpers.TransparentImageButton;
31
import org.distorted.main.MainActivity;
32
import org.distorted.main.R;
33
import org.distorted.objectlib.helpers.ObjectMove;
34
import org.distorted.objectlib.helpers.OperatingSystemInterface;
35
import org.distorted.objectlib.main.ObjectControl;
36
import org.distorted.objectlib.main.TwistyObject;
37
import org.distorted.objectlib.shape.*;
38
import org.distorted.objectlib.solvers.verifiers.ResultScreen;
39
import org.distorted.objectlib.solvers.verifiers.SolverAbstract;
40
import org.distorted.objectlib.solvers.verifiers.ImplementedVerifierList;
41

    
42
import java.lang.ref.WeakReference;
43
import java.util.Timer;
44
import java.util.TimerTask;
45

    
46
///////////////////////////////////////////////////////////////////////////////////////////////////
47

    
48
public class ScreenSetupPosition extends ScreenAbstract implements ResultScreen
49
  {
50
  private static final int RESET_DURATION = 1000;
51
  private static final int MODE_NORMAL = 0;
52
  private static final int MODE_DINO_4 = 1;
53

    
54
  private static Bitmap[] mBitmap;
55
  private ImageButton[] mColorButton;
56
  private TransparentImageButton mResetButton,mBackButton, mSolveButton;
57
  private boolean mSolving;
58
  private int mCurrentColor, mCurrentButton;
59
  private int[] mFaceColors;
60
  private int mColorMode;
61
  private int mNumColors;
62
  private int mNumBitmapRows;
63
  private float mBitmapSize;
64
  private WeakReference<SolverActivity> mWeakAct;
65
  private String mObjectUpperName;
66
  private String[] mPhaseNames;
67
  private Timer mTimer;
68
  private SolverAbstract mSolver;
69

    
70
///////////////////////////////////////////////////////////////////////////////////////////////////
71

    
72
  void leaveScreen(SolverActivity act)
73
    {
74
    ObjectControl control = act.getControl();
75
    control.unsetLock();
76
    }
77

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

    
80
  void enterScreen(final SolverActivity act)
81
    {
82
    ObjectControl control = act.getControl();
83
    control.setLock(false);
84

    
85
    float width = act.getScreenWidthInPixels();
86
    float heigh = act.getScreenHeightInPixels();
87

    
88
    mWeakAct = new WeakReference<>(act);
89
    mSolving = false;
90
    mPhaseNames = null;
91

    
92
    mObjectUpperName = act.getObjectName();
93
    control.solveOnly();
94
    generateFaceColors(mObjectUpperName);
95

    
96
    mNumBitmapRows = mNumColors>8 ? 2 : 1;
97
    mBitmapSize = computeBitmapSize(width,heigh);
98

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

    
103
    if( mNumColors>0 )
104
      {
105
      setupBitmaps();
106
      setupColorButtons(act);
107
      markButton(act);
108
      addButtonsToTopLayout(act,layoutTop);
109
      }
110

    
111
    // BOT ////////////////////////////
112
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1);
113

    
114
    LinearLayout layoutL = new LinearLayout(act);
115
    layoutL.setLayoutParams(params);
116
    LinearLayout layoutM = new LinearLayout(act);
117
    layoutM.setLayoutParams(params);
118
    LinearLayout layoutR = new LinearLayout(act);
119
    layoutR.setLayoutParams(params);
120

    
121
    LinearLayout layoutBot = act.findViewById(R.id.lowerBar);
122
    layoutBot.removeAllViews();
123

    
124
    setupResetButton(act);
125
    setupSolveButton(act);
126
    setupBackButton(act);
127

    
128
    layoutL.addView(mResetButton);
129
    layoutM.addView(mSolveButton);
130
    layoutR.addView(mBackButton);
131

    
132
    layoutBot.addView(layoutL);
133
    layoutBot.addView(layoutM);
134
    layoutBot.addView(layoutR);
135
    }
136

    
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138

    
139
  private float computeBitmapSize(float width, float heigh)
140
    {
141
    final float BUTTON_RATIO = 0.75f;
142
    float sizeV = (heigh/mNumBitmapRows)*MainActivity.RATIO_BAR;
143
    float sizeH = (width*mNumBitmapRows)/mNumColors;
144

    
145
    return BUTTON_RATIO*Math.min(sizeV,sizeH);
146
    }
147

    
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

    
150
  private void addButtonsToTopLayout(SolverActivity act, LinearLayout layout)
151
    {
152
    if( mNumBitmapRows==1 )
153
      {
154
      for(ImageButton button: mColorButton) layout.addView(button);
155
      }
156
    else if( mNumBitmapRows==2 )
157
      {
158
      LinearLayout layoutV = new LinearLayout(act);
159
      layoutV.setOrientation(LinearLayout.VERTICAL);
160
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1);
161
      layoutV.setLayoutParams(params);
162
      LinearLayout layoutT = new LinearLayout(act);
163
      layoutT.setOrientation(LinearLayout.HORIZONTAL);
164
      LinearLayout layoutB = new LinearLayout(act);
165
      layoutB.setOrientation(LinearLayout.HORIZONTAL);
166

    
167
      int numB = mColorButton.length;
168
      for(int b=0     ; b<numB/2; b++) layoutT.addView(mColorButton[b]);
169
      for(int b=numB/2; b<numB  ; b++) layoutB.addView(mColorButton[b]);
170

    
171
      layoutV.addView(layoutT);
172
      layoutV.addView(layoutB);
173
      layout.addView(layoutV);
174
      }
175
    }
176

    
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178
// This doesn't quite work in many cases, but in case of the solvers that will pop up in foreseeable
179
// future it should be ok.
180

    
181
  public void generateFaceColors(String upper)
182
    {
183
    mColorMode = MODE_NORMAL;
184

    
185

    
186
    if( upper.startsWith("PYRA") || upper.startsWith("PDUO") || upper.startsWith("JING") ||
187
        upper.startsWith("MORP") )
188
      {
189
      mNumColors  = ShapeTetrahedron.NUM_FACES;
190
      mFaceColors = ShapeTetrahedron.FACE_COLORS;
191
      }
192
    else if( upper.startsWith("DIAM") || upper.startsWith("TRAJ") || upper.startsWith("PDIA") )
193
      {
194
      mNumColors  = ShapeOctahedron.NUM_FACES;
195
      mFaceColors = ShapeOctahedron.FACE_COLORS;
196
      }
197
    else if( upper.startsWith("CRYS") || upper.startsWith("STAR") || upper.startsWith("PENT") ||
198
             upper.startsWith("KILO") || upper.startsWith("MEGA") )
199
      {
200
      mNumColors  = ShapeDodecahedron.NUM_FACES;
201
      mFaceColors = ShapeDodecahedron.FACE_COLORS;
202
      }
203
    else if( upper.startsWith("BALL") )
204
      {
205
      mNumColors  = ShapeDiamond.NUM_FACES;
206
      mFaceColors = ShapeDiamond.FACE_COLORS;
207
      }
208
    else if( upper.startsWith("ICOS") )
209
      {
210
      mNumColors  = ShapeIcosahedron.NUM_FACES;
211
      mFaceColors = ShapeIcosahedron.FACE_COLORS;
212
      }
213
    else if( upper.startsWith("DIN4") )
214
      {
215
      mNumColors  = 4;
216
      mFaceColors = new int[] { ShapeColors.COLOR_YELLOW, ShapeColors.COLOR_RED, ShapeColors.COLOR_BLUE, ShapeColors.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 pressSolve(SolverActivity act)
276
    {
277
    int[] solverOrdinals = ImplementedVerifierList.getSolverOrdinals(mObjectUpperName);
278

    
279
    if( solverOrdinals!=null  )
280
      {
281
      ImplementedVerifierList slvList = ImplementedVerifierList.getSolver(solverOrdinals[0]);
282
      OperatingSystemInterface os = act.getInterface();
283
      TwistyObject object = act.getObject();
284
      SolverAbstract solver = slvList.create(os,object);
285

    
286
      if( solver!=null )
287
        {
288
        int[] result = solver.validatePosition(object);
289

    
290
        if( result[0]>=0 ) // position is valid
291
          {
292
          if( solverOrdinals.length==1 ) // just one solver - simply launch it
293
            {
294
            mSolver = solver;
295
            solver.solve(this,result);
296
            }
297
          else // more than one solver - pop up a choosing dialog
298
            {
299
            Bundle bundle = new Bundle();
300
            bundle.putString("argument", mObjectUpperName );
301
            DialogSolvers dialog = new DialogSolvers();
302
            dialog.setArguments(bundle);
303
            dialog.show( act.getSupportFragmentManager(), DialogSolvers.getDialogTag());
304
            }
305
          }
306
        else displayImpossibleDialog(result,solver.getFaceColors());
307
        }
308
      else displayErrorDialog(act.getString(R.string.solver_generic_not_implemented));
309
      }
310
    else displayErrorDialog("No solvers found for object "+mObjectUpperName );
311
    }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314

    
315
  public void fail(String result) {}
316
  public void setPhaseNames(String[] names) { mPhaseNames = names; }
317

    
318
///////////////////////////////////////////////////////////////////////////////////////////////////
319

    
320
  void setSolver(SolverAbstract solver )
321
    {
322
    mSolver = solver;
323
    }
324

    
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326

    
327
  public void startedSolving()
328
    {
329
    if( !mSolving )
330
      {
331
      mSolving = true;
332
      mTimer = new Timer();
333

    
334
      mTimer.schedule(new TimerTask()
335
        {
336
        @Override
337
        public void run()
338
          {
339
          if( mSolving ) showInterruptDialog();
340
          }
341
        }, 2000);
342
      }
343
    }
344

    
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346

    
347
  public void stoppedSolving()
348
    {
349
    mSolving = false;
350

    
351
    if( mTimer!=null )
352
      {
353
      mTimer.cancel();
354
      mTimer = null;
355
      }
356

    
357
    final SolverActivity act = mWeakAct.get();
358
    FragmentManager mana = act.getSupportFragmentManager();
359
    DialogInterrupt diag = (DialogInterrupt) mana.findFragmentByTag(DialogInterrupt.getDialogTag());
360

    
361
    if( diag!=null ) diag.dismiss();
362
    }
363

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365

    
366
  void interrupt()
367
    {
368
    final SolverActivity act = mWeakAct.get();
369
    FragmentManager mana = act.getSupportFragmentManager();
370
    DialogInterrupt diag = (DialogInterrupt) mana.findFragmentByTag(DialogInterrupt.getDialogTag());
371

    
372
    if( diag!=null ) diag.dismiss();
373

    
374
    if( mSolver!=null ) mSolver.interrupt();
375
    }
376

    
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378

    
379
    private void showInterruptDialog()
380
      {
381
      final SolverActivity act = mWeakAct.get();
382

    
383
      act.runOnUiThread(new Runnable()
384
        {
385
        @Override
386
        public void run()
387
          {
388
          DialogInterrupt dialog = new DialogInterrupt();
389
          dialog.show(act.getSupportFragmentManager(), null );
390
          }
391
        });
392
      }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395

    
396
  private void setupColorButtons(final SolverActivity act)
397
    {
398
    mColorButton = new ImageButton[mNumColors];
399

    
400
    for(int i=0; i<mNumColors; i++)
401
      {
402
      final int ii = i;
403
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.MATCH_PARENT, 1.0f);
404

    
405
      mColorButton[i] = new ImageButton(act);
406
      mColorButton[i].setLayoutParams(params);
407
      mColorButton[i].setImageBitmap(mBitmap[i]);
408

    
409
      mColorButton[i].setOnClickListener( new View.OnClickListener()
410
        {
411
        @Override
412
        public void onClick(View view)
413
          {
414
          mCurrentColor = translateColor(ii);
415
          mCurrentButton= ii;
416
          markButton(act);
417
          }
418
        });
419
      }
420
    }
421

    
422
///////////////////////////////////////////////////////////////////////////////////////////////////
423

    
424
  private void setupResetButton(final SolverActivity act)
425
    {
426
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);
427
    mResetButton = new TransparentImageButton(act, R.drawable.ui_reset, params);
428

    
429
    mResetButton.setOnClickListener( new View.OnClickListener()
430
      {
431
      @Override
432
      public void onClick(View v)
433
        {
434
        ObjectControl control = act.getControl();
435
        control.resetTextureMapsEffect(RESET_DURATION);
436
        }
437
      });
438
    }
439

    
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441

    
442
  private void setupSolveButton(final SolverActivity act)
443
    {
444
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
445
    mSolveButton = new TransparentImageButton(act,R.drawable.ui_solve,params);
446

    
447
    mSolveButton.setOnClickListener( new View.OnClickListener()
448
      {
449
      @Override
450
      public void onClick(View v)
451
        {
452
        if( !mSolving ) pressSolve(act);
453
        }
454
      });
455
    }
456

    
457
///////////////////////////////////////////////////////////////////////////////////////////////////
458

    
459
  private void setupBackButton(final SolverActivity act)
460
    {
461
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
462
    mBackButton = new TransparentImageButton(act,R.drawable.ui_back,params);
463

    
464
    mBackButton.setOnClickListener( new View.OnClickListener()
465
      {
466
      @Override
467
      public void onClick(View v)
468
        {
469
        ObjectControl control = act.getControl();
470
        control.resetAllTextureMaps();
471
        ScreenList.goBack(act);
472
        }
473
      });
474
    }
475

    
476
///////////////////////////////////////////////////////////////////////////////////////////////////
477

    
478
  private void markButton(SolverActivity act)
479
    {
480
    if( mCurrentButton>=mNumColors )
481
      {
482
      mCurrentButton = 0;
483
      mCurrentColor = translateColor(0);
484
      }
485

    
486
    for(int b=0; b<mNumColors; b++)
487
      {
488
      Drawable d = mColorButton[b].getBackground();
489
      int s = b==mCurrentButton ? act.getSelectedColor() : act.getNormalColor();
490
      d.setColorFilter(ContextCompat.getColor(act,s), PorterDuff.Mode.MULTIPLY);
491
      }
492
    }
493

    
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495

    
496
  public void savePreferences(SharedPreferences.Editor editor)
497
    {
498
    editor.putInt("stateSolver_color" , mCurrentColor );
499
    editor.putInt("stateSolver_button", mCurrentButton);
500
    }
501

    
502
///////////////////////////////////////////////////////////////////////////////////////////////////
503

    
504
  public void restorePreferences(SharedPreferences preferences)
505
    {
506
    mCurrentColor = preferences.getInt("stateSolver_color" , 0);
507
    mCurrentButton= preferences.getInt("stateSolver_button", 0);
508
    }
509

    
510
///////////////////////////////////////////////////////////////////////////////////////////////////
511

    
512
  public int getCurrentColor()
513
    {
514
    return mCurrentColor;
515
    }
516

    
517
///////////////////////////////////////////////////////////////////////////////////////////////////
518

    
519
  public void setSolved(final ObjectMove[] moves, final int phaseNumber, final int[][] subphases)
520
    {
521
    final SolverActivity act = mWeakAct.get();
522

    
523
    if( act!=null )
524
      {
525
      act.runOnUiThread(new Runnable()
526
        {
527
        @Override
528
        public void run()
529
          {
530
          if( mPhaseNames!=null )
531
            {
532
            ScreenSolutionMultiphased screen = (ScreenSolutionMultiphased) ScreenList.PHAS.getScreenClass();
533
            if( phaseNumber==0 )
534
              {
535
              ScreenList.switchScreen(act, ScreenList.PHAS);
536
              screen.updateNames(mPhaseNames);
537
              }
538
            screen.setSolution(moves, phaseNumber,subphases);
539
            }
540
          else
541
            {
542
            ScreenList.switchScreen(act, ScreenList.SOLU);
543
            ScreenSolutionSinglephased screen = (ScreenSolutionSinglephased) ScreenList.SOLU.getScreenClass();
544
            screen.setSolution(moves);
545
            }
546

    
547
          if( moves!=null && moves.length>0 ) act.doNotShowDialogAnymore();
548
          }
549
        });
550
      }
551
    }
552

    
553
///////////////////////////////////////////////////////////////////////////////////////////////////
554

    
555
  public void displayErrorDialog(String message)
556
    {
557
    SolverActivity act = mWeakAct.get();
558

    
559
    if( act!=null )
560
      {
561
      DialogSolverError dialog = new DialogSolverError();
562
      Bundle bundle = new Bundle();
563
      bundle.putString("argument", message );
564
      dialog.setArguments(bundle);
565
      dialog.show( act.getSupportFragmentManager(), null);
566
      }
567
    }
568

    
569
///////////////////////////////////////////////////////////////////////////////////////////////////
570

    
571
  public void displayImpossibleDialog(String message)
572
    {
573
    SolverActivity act = mWeakAct.get();
574

    
575
    if( act!=null )
576
      {
577
      DialogSolverImpossible dialog = new DialogSolverImpossible();
578
      Bundle bundle = new Bundle();
579
      bundle.putString("argument", message );
580
      dialog.setArguments(bundle);
581
      dialog.show( act.getSupportFragmentManager(), null);
582
      }
583
    }
584

    
585
///////////////////////////////////////////////////////////////////////////////////////////////////
586

    
587
  public void displayImpossibleDialog(int[] errorCode, int[] faceColors)
588
    {
589
    SolverActivity act = mWeakAct.get();
590

    
591
    if( act!=null )
592
      {
593
      String message = SolverErrors.error(act.getResources(),errorCode,faceColors);
594
      displayImpossibleDialog(message);
595
      }
596
    }
597
  }
(3-3/11)