Project

General

Profile

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

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

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