Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / ScreenSolutionMultiphased.java @ 68484d1b

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 034c66e2 leszek
      @Override public void onClick(View v) { ScreenList.goBack(act); }
241 2f53a016 leszek
      });
242
    }
243
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245
246
  public void savePreferences(SharedPreferences.Editor editor) { }
247
  public void restorePreferences(SharedPreferences preferences) { }
248
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250
251
  void backPhase()
252
    {
253
    SolverActivity act = mAct.get();
254
    ObjectControl control = act.getControl();
255
256
    if( mCurrMove>0 )
257
      {
258
      int[][] moves = transformMoves(mMoves[mCurrPhase],0,mCurrMove, false);
259
      control.applyScrambles(moves);
260
      mCurrMove = 0;
261
      }
262
    else if( mCurrPhase>0 )
263
      {
264
      mCurrPhase--;
265
      mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
266
      mCurrMove = 0;
267
      int[][] moves = transformMoves(mMoves[mCurrPhase],0,mNumMoves, false);
268
      control.applyScrambles(moves);
269
      }
270
    else
271
      {
272
      mCurrPhase = mNumPhases-1;
273
      mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
274
      mCurrMove = mNumMoves;
275
      int[][] moves = transformMoves(mMoves, true);
276
      control.applyScrambles(moves);
277
      }
278
279
    setText(act);
280
    }
281
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283
284
  void nextPhase()
285
    {
286
    SolverActivity act = mAct.get();
287
    ObjectControl control = act.getControl();
288
289
    if( mCurrPhase<mNumPhases-1 )
290
      {
291
      glowCubits(mCubitsNotInvolved[mCurrPhase]);
292
      int[][] moves = transformMoves(mMoves[mCurrPhase],mCurrMove,mNumMoves, true);
293
      control.applyScrambles(moves);
294
      mCurrPhase++;
295
      mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
296
      mCurrMove = 0;
297
      }
298
    else if( mCurrMove<mNumMoves )
299
      {
300
      glowCubits(mCubitsNotInvolved[mCurrPhase]);
301
      int[][] moves = transformMoves(mMoves[mCurrPhase],mCurrMove,mNumMoves, true);
302
      control.applyScrambles(moves);
303
      mCurrMove = mNumMoves;
304
      }
305
    else
306
      {
307
      mCurrPhase = 0;
308
      mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
309
      mCurrMove = 0;
310
      int[][] moves = transformMoves(mMoves, false);
311
      control.applyScrambles(moves);
312
      }
313
314
    setText(act);
315
    }
316
317
///////////////////////////////////////////////////////////////////////////////////////////////////
318
319
  private void setText(SolverActivity act)
320
    {
321
    int currMove = 0;
322
    int totalMove = 0;
323
324
    if( mMoves!=null )
325
      {
326
      currMove = mCurrMove;
327
      for(int p=0; p<mCurrPhase; p++) currMove  += (mMoves[p]==null ? 0: mMoves[p].length);
328
      for(int p=0; p<mNumPhases; p++) totalMove += (mMoves[p]==null ? 0: mMoves[p].length);
329
      }
330
331
    final int cMove = currMove;
332
    final int tMove = totalMove;
333
334
    act.runOnUiThread(new Runnable()
335
      {
336
      @Override
337
      public void run()
338
        {
339 034c66e2 leszek
        mMovesPhase.setText(act.getString(R.string.ph_placeholder,mPhaseNames[mCurrPhase],mCurrMove,mNumMoves));
340
        mMovesText.setText(act.getString(R.string.mo_placeholder,cMove,tMove));
341 2f53a016 leszek
        }
342
      });
343
    }
344
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346
347
  private int[][] transformMoves(int[][] moves, int start, int end, boolean front)
348
    {
349
    int mult = front ? 1:-1;
350
    int len = end-start;
351
    int[][] ret = new int[len][];
352
353
    for(int m=0; m<len; m++)
354
      {
355
      int[] mv = moves[front ? start+m : end-1-m];
356
      int[] rt = new int[3];
357
      rt[0] = mv[0];
358
      rt[1] = (1<<mv[1]);
359
      rt[2] = mult*mv[2];
360
      ret[m] = rt;
361
      }
362
363
    return ret;
364
    }
365
366
///////////////////////////////////////////////////////////////////////////////////////////////////
367
368
  private int[][] transformMoves(int[][][] moves, boolean front)
369
    {
370
    int len = moves.length;
371
    int totalLen = 0;
372
    for (int[][] move : moves) totalLen += (move==null ? 0 : move.length);
373
374
    int[][] ret = new int[totalLen][];
375
    int mult = front ? 1:-1;
376
    int index = 0;
377
378
    for(int m=0; m<len; m++)
379
      {
380
      int[][] mv = moves[front ? m : len-1-m];
381
      int l = (mv==null ? 0 : mv.length);
382
383
      for(int p=0; p<l; p++)
384
        {
385
        int[] mve = mv[front ? p : l-1-p];
386
        int[] rt = new int[3];
387
        rt[0] = mve[0];
388
        rt[1] = (1<<mve[1]);
389
        rt[2] = mult*mve[2];
390
        ret[index++] = rt;
391
        }
392
      }
393
394
    return ret;
395
    }
396
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398
399
  private void glowCubits(int[] cubits)
400
    {
401
    if( !mEffectWorking )
402
      {
403
      mEffectWorking = true;
404
      SolverActivity act=mAct.get();
405
      ObjectControl control = act.getControl();
406
      TwistyObject object=control.getObject();
407
      DistortedEffects effects=object.getObjectEffects();
408
      effects.apply(mGlow);
409
410
      MeshBase mesh=object.getObjectMesh();
411
      mesh.setComponentsNotAffectedByPostprocessing(cubits);
412
413
      mHaloAndRadiusDyn.resetToBeginning();
414
      mColorDyn.resetToBeginning();
415
      mGlow.notifyWhenFinished(this);
416
      }
417
    }
418
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420
421
  private int[] computeCubitsNotInvolved(int[][] subphases, int numCubits)
422
    {
423
    int numCubitsInvolved = 0;
424
    boolean[] involved = new boolean[numCubits];
425
426
    for(int[] sub : subphases)
427
      if( sub!=null )
428
        for(int s : sub)
429
          {
430
          numCubitsInvolved++;
431
          involved[s] = true;
432
          }
433
434
    int[] ret = new int[numCubits-numCubitsInvolved];
435
    int index = 0;
436
437
    for(int c=0; c<numCubits; c++)
438
      if( !involved[c] ) ret[index++] = c;
439
440
    return ret;
441
    }
442
443
///////////////////////////////////////////////////////////////////////////////////////////////////
444
445
  void backMove()
446
    {
447
    if( mMoves!=null && mCanMove )
448
      {
449
      SolverActivity act=mAct.get();
450
451
      if( mCurrMove>0 )
452
        {
453
        mCanMove = false;
454
        int[] move = mMoves[mCurrPhase][--mCurrMove];
455
        ObjectControl control = act.getControl();
456
        control.blockTouch(MOVES_PLACE_0);
457
        control.addRotation(this, move[0], (1<<move[1]), -move[2], MILLIS_PER_DEGREE);
458
        }
459
      else if( mCurrPhase>0 )
460
        {
461
        mCurrPhase--;
462
        mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
463
        mCurrMove = mNumMoves;
464
        glowCubits(mCubitsNotInvolved[mCurrPhase]);
465
        }
466
      else
467
        {
468
        mCurrPhase = mNumPhases-1;
469
        mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
470
        mCurrMove = mNumMoves;
471
        int[][] moves = transformMoves(mMoves, true);
472
        ObjectControl control = act.getControl();
473
        control.applyScrambles(moves);
474
        glowCubits(mCubitsNotInvolved[mCurrPhase]);
475
        }
476
477
      setText(act);
478
      }
479
    }
480
481
///////////////////////////////////////////////////////////////////////////////////////////////////
482
483
  void nextMove()
484
    {
485
    if( mMoves!=null && mCanMove )
486
      {
487
      SolverActivity act=mAct.get();
488
489
      if( mCurrMove<mNumMoves )
490
        {
491
        mCanMove = false;
492
        int[] move = mMoves[mCurrPhase][mCurrMove++];
493
        ObjectControl control = act.getControl();
494
        control.blockTouch(MOVES_PLACE_1);
495
        control.addRotation(this, move[0], (1<<move[1]), move[2], MILLIS_PER_DEGREE);
496
        if( mCurrMove==mNumMoves && mCurrPhase==mNumPhases-1 ) glowCubits(mCubitsNotInvolved[mCurrPhase]);
497
        }
498
      else if( mCurrPhase<mNumPhases-1 )
499
        {
500
        mCurrPhase++;
501
        mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
502
        mCurrMove = 0;
503
        glowCubits(mCubitsNotInvolved[mCurrPhase-1]);
504
        }
505
      else
506
        {
507
        mCurrPhase = 0;
508
        mNumMoves = mMoves[mCurrPhase]==null ? 0 : mMoves[mCurrPhase].length;
509
        mCurrMove = 0;
510
        int[][] moves = transformMoves(mMoves, false);
511
        ObjectControl control = act.getControl();
512
        control.applyScrambles(moves);
513
        }
514
515
      setText(act);
516
      }
517
    }
518
519
///////////////////////////////////////////////////////////////////////////////////////////////////
520
521
  public void updateNames(String[] names)
522
    {
523
    mPhaseNames = names;
524
    mNumPhases = names.length;
525
    mMoves = new int[mNumPhases][][];
526
    mCubitsNotInvolved = new int[mNumPhases][];
527
    mCanMove = true;
528
    if( mAct!=null ) setSolution(null,0,null);
529
    }
530
531
///////////////////////////////////////////////////////////////////////////////////////////////////
532
533
  public void setSolution(int[][] moves, int phase, int[][] subphases)
534
    {
535
    SolverActivity act=mAct.get();
536
537
    if( subphases!=null )
538
      {
539
      ObjectControl control=act.getControl();
540
      TwistyObject object=control.getObject();
541
      int numCubits=object.getNumCubits();
542
      mCubitsNotInvolved[phase]= computeCubitsNotInvolved(subphases, numCubits);
543
      }
544
545
    mMoves[phase] = moves;
546
    if( phase==0 ) mNumMoves = (moves==null ? 0 : moves.length);
547
    mCurrPhase = 0;
548
    mCurrMove = 0;
549
550
    setText(act);
551
    }
552
553
///////////////////////////////////////////////////////////////////////////////////////////////////
554
555
  public void onActionFinished(final long effectID)
556
    {
557
    mCanMove = true;
558
    SolverActivity act=mAct.get();
559
    ObjectControl control = act.getControl();
560
    control.unblockRotation();
561
    }
562
563
///////////////////////////////////////////////////////////////////////////////////////////////////
564
565
  public void effectFinished(long id)
566
    {
567
    SolverActivity act=mAct.get();
568
    ObjectControl control = act.getControl();
569
    TwistyObject object=control.getObject();
570
    DistortedEffects effects=object.getObjectEffects();
571
    effects.abortById(id);
572
    mEffectWorking = false;
573
    }
574
  }