Project

General

Profile

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

magiccube / src / main / java / org / distorted / solvers / ScreenSolutionMultiphased.java @ 7d574482

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