Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / ScreenSolutionMultiphased.java @ b3278db6

1 2f53a016 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2024 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 7e9d918b leszek
package org.distorted.solvers;
11 2f53a016 leszek
12
import android.content.SharedPreferences;
13
import android.util.TypedValue;
14
import android.view.Gravity;
15
import android.view.View;
16
import android.widget.LinearLayout;
17
import android.widget.TextView;
18
19
import org.distorted.helpers.TransparentImageButton;
20
import org.distorted.library.effect.PostprocessEffectGlow;
21
import org.distorted.library.main.DistortedEffects;
22
import org.distorted.library.mesh.MeshBase;
23
import org.distorted.library.message.EffectListener;
24
import org.distorted.library.type.Dynamic2D;
25
import org.distorted.library.type.Dynamic4D;
26
import org.distorted.library.type.Static2D;
27
import org.distorted.library.type.Static4D;
28
import org.distorted.main.R;
29
import org.distorted.objectlib.helpers.MovesFinished;
30
import org.distorted.objectlib.main.ObjectControl;
31
import org.distorted.objectlib.main.TwistyObject;
32
33
import java.lang.ref.WeakReference;
34
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36
37 a742d66b leszek
public class ScreenSolutionMultiphased extends ScreenAbstract implements MovesFinished, EffectListener
38 2f53a016 leszek
  {
39
  private static final int MOVES_PLACE_0 = 100;
40
  private static final int MOVES_PLACE_1 = 101;
41
  private static final int FLASH_TIME = 1200;
42
  private static final int MILLIS_PER_DEGREE = 6;
43
44
  private WeakReference<SolverActivity> mAct;
45
  private TransparentImageButton mPrevButton, mNextButton, mBackButton, mPrevPhase, mNextPhase;
46
  private float mButtonSize;
47
48
  private TextView mMovesText, mMovesPhase;
49
  private String[] mPhaseNames;
50
  private int mNumPhases;
51
  private int[][][] mMoves;
52
  private int[][] mCubitsNotInvolved;
53
  private int mNumMoves,mCurrMove,mCurrPhase;
54
  private boolean mCanMove;
55
56
  private Dynamic2D mHaloAndRadiusDyn;
57
  private Dynamic4D mColorDyn;
58
  private PostprocessEffectGlow mGlow;
59
  private boolean mEffectWorking;
60
61
///////////////////////////////////////////////////////////////////////////////////////////////////
62
63
  void leaveScreen(SolverActivity act)
64
    {
65
    ObjectControl control = act.getControl();
66
    control.solveOnly();
67
    }
68
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70
71
  void enterScreen(final SolverActivity act)
72
    {
73
    mAct = new WeakReference<>(act);
74
75
    mHaloAndRadiusDyn = new Dynamic2D(FLASH_TIME,1.0f);
76
    mHaloAndRadiusDyn.add(new Static2D( 0,0));
77
    mHaloAndRadiusDyn.add(new Static2D(10,5));
78
79
    mColorDyn = new Dynamic4D(FLASH_TIME,1.0f);
80
81
    final int[] colors  = new int[] {1,1,1}; // white
82
83
    Static4D P1 = new Static4D(colors[0],colors[1],colors[2], 0.0f);
84
    Static4D P2 = new Static4D(colors[0],colors[1],colors[2], 1.0f);
85
    mColorDyn.add(P1);
86
    mColorDyn.add(P2);
87
88
    mGlow = new PostprocessEffectGlow(mHaloAndRadiusDyn,mColorDyn);
89
90
    float width = act.getScreenWidthInPixels();
91
    mButtonSize = width*SolverActivity.BUTTON_TEXT_SIZE;
92
93
    // TOP ////////////////////////////
94
    LinearLayout layoutTop = act.findViewById(R.id.upperBar);
95
    layoutTop.removeAllViews();
96
97
    setupPrevPhase(act);
98
    setupNextPhase(act);
99
    setupTextPhase(act,width);
100
101
    layoutTop.addView(mPrevPhase);
102
    layoutTop.addView(mMovesPhase);
103
    layoutTop.addView(mNextPhase);
104
105
    // BOT ////////////////////////////
106
    LinearLayout layoutBot = act.findViewById(R.id.lowerBar);
107
    layoutBot.removeAllViews();
108
109
    LinearLayout.LayoutParams paramsL = new LinearLayout.LayoutParams((int)(width/2),LinearLayout.LayoutParams.MATCH_PARENT);
110
    LinearLayout.LayoutParams paramsM = new LinearLayout.LayoutParams((int)(width/6),LinearLayout.LayoutParams.MATCH_PARENT);
111
    LinearLayout.LayoutParams paramsR = new LinearLayout.LayoutParams((int)(width/3),LinearLayout.LayoutParams.MATCH_PARENT);
112
113
    LinearLayout layoutLeft = new LinearLayout(act);
114
    layoutLeft.setLayoutParams(paramsL);
115
    LinearLayout layoutMid = new LinearLayout(act);
116
    layoutMid.setLayoutParams(paramsM);
117
    LinearLayout layoutRight = new LinearLayout(act);
118
    layoutRight.setLayoutParams(paramsR);
119
120
    setupPrevButton(act);
121
    setupNextButton(act);
122
    setupTextView(act,width);
123
124
    layoutLeft.addView(mPrevButton);
125
    layoutLeft.addView(mMovesText);
126
    layoutLeft.addView(mNextButton);
127
128
    setupBackButton(act);
129
130
    layoutRight.addView(mBackButton);
131
132
    layoutBot.addView(layoutLeft);
133
    layoutBot.addView(layoutMid);
134
    layoutBot.addView(layoutRight);
135
    }
136
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138
139
  private void setupPrevButton(final SolverActivity act)
140
    {
141
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
142
    mPrevButton = new TransparentImageButton(act,R.drawable.ui_left,params);
143
144
    mPrevButton.setOnClickListener( new View.OnClickListener()
145
      {
146
      @Override public void onClick(View v) { backMove(); }
147
      });
148
    }
149
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151
152
  private void setupNextButton(final SolverActivity act)
153
    {
154
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
155
    mNextButton = new TransparentImageButton(act,R.drawable.ui_right,params);
156
157
    mNextButton.setOnClickListener( new View.OnClickListener()
158
      {
159
      @Override public void onClick(View v) { nextMove(); }
160
      });
161
    }
162
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164
165
  private void setupTextView(final SolverActivity act, final float width)
166
    {
167
    int padding = (int)(width*SolverActivity.PADDING);
168
    int margin  = (int)(width*SolverActivity.SMALL_MARGIN);
169
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,2.0f);
170
    params.topMargin    = margin;
171
    params.bottomMargin = margin;
172
    params.leftMargin   = margin;
173
    params.rightMargin  = margin;
174
175
    mMovesText = new TextView(act);
176
    mMovesText.setTextSize(20);
177
    mMovesText.setLayoutParams(params);
178
    mMovesText.setPadding(padding,0,padding,0);
179
    mMovesText.setGravity(Gravity.CENTER);
180
    mMovesText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mButtonSize);
181
    mMovesText.setText(act.getString(R.string.mo_placeholder,mCurrMove,mNumMoves));
182
    }
183
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185
186
  private void setupPrevPhase(final SolverActivity act)
187
    {
188
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
189
    mPrevPhase = new TransparentImageButton(act,R.drawable.ui_left,params);
190
191
    mPrevPhase.setOnClickListener( new View.OnClickListener()
192
      {
193
      @Override public void onClick(View v) { backPhase(); }
194
      });
195
    }
196
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198
199
  private void setupNextPhase(final SolverActivity act)
200
    {
201
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
202
    mNextPhase = new TransparentImageButton(act,R.drawable.ui_right,params);
203
204
    mNextPhase.setOnClickListener( new View.OnClickListener()
205
      {
206
      @Override public void onClick(View v) { nextPhase(); }
207
      });
208
    }
209
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211
212
  private void setupTextPhase(final SolverActivity act, final float width)
213
    {
214
    int padding = (int)(width*SolverActivity.PADDING);
215
    int margin  = (int)(width*SolverActivity.SMALL_MARGIN);
216
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.MATCH_PARENT,2.0f);
217
    params.topMargin    = margin;
218
    params.bottomMargin = margin;
219
    params.leftMargin   = margin;
220
    params.rightMargin  = margin;
221
222
    mMovesPhase = new TextView(act);
223
    mMovesPhase.setTextSize(20);
224
    mMovesPhase.setLayoutParams(params);
225
    mMovesPhase.setPadding(padding,0,padding,0);
226
    mMovesPhase.setGravity(Gravity.CENTER);
227
    mMovesPhase.setTextSize(TypedValue.COMPLEX_UNIT_PX, mButtonSize);
228
    mMovesPhase.setText(act.getString(R.string.mo_placeholder,mCurrMove,mNumMoves));
229
    }
230
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232
233
  private void setupBackButton(final SolverActivity act)
234
    {
235
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT,1.0f);
236
    mBackButton = new TransparentImageButton(act,R.drawable.ui_back,params);
237
238
    mBackButton.setOnClickListener( new View.OnClickListener()
239
      {
240
      @Override
241
      public void onClick(View v)
242
        {
243
        ScreenList.goBack(act);
244
        }
245
      });
246
    }
247
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
250
  public void savePreferences(SharedPreferences.Editor editor) { }
251
  public void restorePreferences(SharedPreferences preferences) { }
252
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254
255
  void backPhase()
256
    {
257
    SolverActivity act = mAct.get();
258
    ObjectControl control = act.getControl();
259
260
    if( mCurrMove>0 )
261
      {
262
      int[][] moves = transformMoves(mMoves[mCurrPhase],0,mCurrMove, false);
263
      control.applyScrambles(moves);
264
      mCurrMove = 0;
265
      }
266
    else if( mCurrPhase>0 )
267
      {
268
      mCurrPhase--;
269
      mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
270
      mCurrMove = 0;
271
      int[][] moves = transformMoves(mMoves[mCurrPhase],0,mNumMoves, false);
272
      control.applyScrambles(moves);
273
      }
274
    else
275
      {
276
      mCurrPhase = mNumPhases-1;
277
      mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
278
      mCurrMove = mNumMoves;
279
      int[][] moves = transformMoves(mMoves, true);
280
      control.applyScrambles(moves);
281
      }
282
283
    setText(act);
284
    }
285
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287
288
  void nextPhase()
289
    {
290
    SolverActivity act = mAct.get();
291
    ObjectControl control = act.getControl();
292
293
    if( mCurrPhase<mNumPhases-1 )
294
      {
295
      glowCubits(mCubitsNotInvolved[mCurrPhase]);
296
      int[][] moves = transformMoves(mMoves[mCurrPhase],mCurrMove,mNumMoves, true);
297
      control.applyScrambles(moves);
298
      mCurrPhase++;
299
      mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
300
      mCurrMove = 0;
301
      }
302
    else if( mCurrMove<mNumMoves )
303
      {
304
      glowCubits(mCubitsNotInvolved[mCurrPhase]);
305
      int[][] moves = transformMoves(mMoves[mCurrPhase],mCurrMove,mNumMoves, true);
306
      control.applyScrambles(moves);
307
      mCurrMove = mNumMoves;
308
      }
309
    else
310
      {
311
      mCurrPhase = 0;
312
      mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
313
      mCurrMove = 0;
314
      int[][] moves = transformMoves(mMoves, false);
315
      control.applyScrambles(moves);
316
      }
317
318
    setText(act);
319
    }
320
321
///////////////////////////////////////////////////////////////////////////////////////////////////
322
323
  private void setText(SolverActivity act)
324
    {
325
    int currMove = 0;
326
    int totalMove = 0;
327
328
    if( mMoves!=null )
329
      {
330
      currMove = mCurrMove;
331
      for(int p=0; p<mCurrPhase; p++) currMove  += (mMoves[p]==null ? 0: mMoves[p].length);
332
      for(int p=0; p<mNumPhases; p++) totalMove += (mMoves[p]==null ? 0: mMoves[p].length);
333
      }
334
335
    final int cMove = currMove;
336
    final int tMove = totalMove;
337
338
    act.runOnUiThread(new Runnable()
339
      {
340
      @Override
341
      public void run()
342
        {
343
        mMovesPhase.setText(mPhaseNames[mCurrPhase]+" "+mCurrMove+"/"+mNumMoves);
344
        mMovesText.setText(cMove+"/"+tMove);
345
        }
346
      });
347
    }
348
349
///////////////////////////////////////////////////////////////////////////////////////////////////
350
351
  private int[][] transformMoves(int[][] moves, int start, int end, boolean front)
352
    {
353
    int mult = front ? 1:-1;
354
    int len = end-start;
355
    int[][] ret = new int[len][];
356
357
    for(int m=0; m<len; m++)
358
      {
359
      int[] mv = moves[front ? start+m : end-1-m];
360
      int[] rt = new int[3];
361
      rt[0] = mv[0];
362
      rt[1] = (1<<mv[1]);
363
      rt[2] = mult*mv[2];
364
      ret[m] = rt;
365
      }
366
367
    return ret;
368
    }
369
370
///////////////////////////////////////////////////////////////////////////////////////////////////
371
372
  private int[][] transformMoves(int[][][] moves, boolean front)
373
    {
374
    int len = moves.length;
375
    int totalLen = 0;
376
    for (int[][] move : moves) totalLen += (move==null ? 0 : move.length);
377
378
    int[][] ret = new int[totalLen][];
379
    int mult = front ? 1:-1;
380
    int index = 0;
381
382
    for(int m=0; m<len; m++)
383
      {
384
      int[][] mv = moves[front ? m : len-1-m];
385
      int l = (mv==null ? 0 : mv.length);
386
387
      for(int p=0; p<l; p++)
388
        {
389
        int[] mve = mv[front ? p : l-1-p];
390
        int[] rt = new int[3];
391
        rt[0] = mve[0];
392
        rt[1] = (1<<mve[1]);
393
        rt[2] = mult*mve[2];
394
        ret[index++] = rt;
395
        }
396
      }
397
398
    return ret;
399
    }
400
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402
403
  private void glowCubits(int[] cubits)
404
    {
405
    if( !mEffectWorking )
406
      {
407
      mEffectWorking = true;
408
      SolverActivity act=mAct.get();
409
      ObjectControl control = act.getControl();
410
      TwistyObject object=control.getObject();
411
      DistortedEffects effects=object.getObjectEffects();
412
      effects.apply(mGlow);
413
414
      MeshBase mesh=object.getObjectMesh();
415
      mesh.setComponentsNotAffectedByPostprocessing(cubits);
416
417
      mHaloAndRadiusDyn.resetToBeginning();
418
      mColorDyn.resetToBeginning();
419
      mGlow.notifyWhenFinished(this);
420
      }
421
    }
422
423
///////////////////////////////////////////////////////////////////////////////////////////////////
424
425
  private int[] computeCubitsNotInvolved(int[][] subphases, int numCubits)
426
    {
427
    int numCubitsInvolved = 0;
428
    boolean[] involved = new boolean[numCubits];
429
430
    for(int[] sub : subphases)
431
      if( sub!=null )
432
        for(int s : sub)
433
          {
434
          numCubitsInvolved++;
435
          involved[s] = true;
436
          }
437
438
    int[] ret = new int[numCubits-numCubitsInvolved];
439
    int index = 0;
440
441
    for(int c=0; c<numCubits; c++)
442
      if( !involved[c] ) ret[index++] = c;
443
444
    return ret;
445
    }
446
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448
449
  void backMove()
450
    {
451
    if( mMoves!=null && mCanMove )
452
      {
453
      SolverActivity act=mAct.get();
454
455
      if( mCurrMove>0 )
456
        {
457
        mCanMove = false;
458
        int[] move = mMoves[mCurrPhase][--mCurrMove];
459
        ObjectControl control = act.getControl();
460
        control.blockTouch(MOVES_PLACE_0);
461
        control.addRotation(this, move[0], (1<<move[1]), -move[2], MILLIS_PER_DEGREE);
462
        }
463
      else if( mCurrPhase>0 )
464
        {
465
        mCurrPhase--;
466
        mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
467
        mCurrMove = mNumMoves;
468
        glowCubits(mCubitsNotInvolved[mCurrPhase]);
469
        }
470
      else
471
        {
472
        mCurrPhase = mNumPhases-1;
473
        mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
474
        mCurrMove = mNumMoves;
475
        int[][] moves = transformMoves(mMoves, true);
476
        ObjectControl control = act.getControl();
477
        control.applyScrambles(moves);
478
        glowCubits(mCubitsNotInvolved[mCurrPhase]);
479
        }
480
481
      setText(act);
482
      }
483
    }
484
485
///////////////////////////////////////////////////////////////////////////////////////////////////
486
487
  void nextMove()
488
    {
489
    if( mMoves!=null && mCanMove )
490
      {
491
      SolverActivity act=mAct.get();
492
493
      if( mCurrMove<mNumMoves )
494
        {
495
        mCanMove = false;
496
        int[] move = mMoves[mCurrPhase][mCurrMove++];
497
        ObjectControl control = act.getControl();
498
        control.blockTouch(MOVES_PLACE_1);
499
        control.addRotation(this, move[0], (1<<move[1]), move[2], MILLIS_PER_DEGREE);
500
        if( mCurrMove==mNumMoves && mCurrPhase==mNumPhases-1 ) glowCubits(mCubitsNotInvolved[mCurrPhase]);
501
        }
502
      else if( mCurrPhase<mNumPhases-1 )
503
        {
504
        mCurrPhase++;
505
        mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
506
        mCurrMove = 0;
507
        glowCubits(mCubitsNotInvolved[mCurrPhase-1]);
508
        }
509
      else
510
        {
511
        mCurrPhase = 0;
512
        mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
513
        mCurrMove = 0;
514
        int[][] moves = transformMoves(mMoves, false);
515
        ObjectControl control = act.getControl();
516
        control.applyScrambles(moves);
517
        }
518
519
      setText(act);
520
      }
521
    }
522
523
///////////////////////////////////////////////////////////////////////////////////////////////////
524
525
  public void updateNames(String[] names)
526
    {
527
    mPhaseNames = names;
528
    mNumPhases = names.length;
529
    mMoves = new int[mNumPhases][][];
530
    mCubitsNotInvolved = new int[mNumPhases][];
531
    mCanMove = true;
532
    if( mAct!=null ) setSolution(null,0,null);
533
    }
534
535
///////////////////////////////////////////////////////////////////////////////////////////////////
536
537
  public void setSolution(int[][] moves, int phase, int[][] subphases)
538
    {
539
    SolverActivity act=mAct.get();
540
541
    if( subphases!=null )
542
      {
543
      ObjectControl control=act.getControl();
544
      TwistyObject object=control.getObject();
545
      int numCubits=object.getNumCubits();
546
      mCubitsNotInvolved[phase]= computeCubitsNotInvolved(subphases, numCubits);
547
      }
548
549
    mMoves[phase] = moves;
550
    if( phase==0 ) mNumMoves = (moves==null ? 0 : moves.length);
551
    mCurrPhase = 0;
552
    mCurrMove = 0;
553
554
    setText(act);
555
    }
556
557
///////////////////////////////////////////////////////////////////////////////////////////////////
558
559
  public void onActionFinished(final long effectID)
560
    {
561
    mCanMove = true;
562
    SolverActivity act=mAct.get();
563
    ObjectControl control = act.getControl();
564
    control.unblockRotation();
565
    }
566
567
///////////////////////////////////////////////////////////////////////////////////////////////////
568
569
  public void effectFinished(long id)
570
    {
571
    SolverActivity act=mAct.get();
572
    ObjectControl control = act.getControl();
573
    TwistyObject object=control.getObject();
574
    DistortedEffects effects=object.getObjectEffects();
575
    effects.abortById(id);
576
    mEffectWorking = false;
577
    }
578
  }