Project

General

Profile

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

magiccube / src / main / java / org / distorted / effects / scramble / ScrambleEffect.java @ 5cf34c5f

1 3b12e641 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4 fdec60a3 Leszek Koltunski
// This file is part of Magic Cube.                                                              //
5 3b12e641 Leszek Koltunski
//                                                                                               //
6 fdec60a3 Leszek Koltunski
// Magic Cube is free software: you can redistribute it and/or modify                            //
7 3b12e641 Leszek Koltunski
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11 fdec60a3 Leszek Koltunski
// Magic Cube is distributed in the hope that it will be useful,                                 //
12 3b12e641 Leszek Koltunski
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17 fdec60a3 Leszek Koltunski
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18 3b12e641 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20 1f9772f3 Leszek Koltunski
package org.distorted.effects.scramble;
21 3b12e641 Leszek Koltunski
22 1f9772f3 Leszek Koltunski
import org.distorted.effects.BaseEffect;
23 3b12e641 Leszek Koltunski
import org.distorted.library.effect.Effect;
24
import org.distorted.library.main.DistortedEffects;
25 8becce57 Leszek Koltunski
import org.distorted.library.main.DistortedScreen;
26 3b12e641 Leszek Koltunski
import org.distorted.library.message.EffectListener;
27 1f9772f3 Leszek Koltunski
import org.distorted.main.RubikPostRender;
28
import org.distorted.objects.RubikObject;
29 3b12e641 Leszek Koltunski
30
import java.lang.reflect.Method;
31 e8764a49 Leszek Koltunski
import java.util.Random;
32 3b12e641 Leszek Koltunski
33
///////////////////////////////////////////////////////////////////////////////////////////////////
34
35 8becce57 Leszek Koltunski
public abstract class ScrambleEffect extends BaseEffect implements EffectListener, RubikPostRender.ActionFinishedListener
36 3b12e641 Leszek Koltunski
{
37
  public enum Type
38
    {
39
    NONE         (ScrambleEffectNone.class        ),
40 a62aa9d7 Leszek Koltunski
    ROTATIONS    (ScrambleEffectRotations.class   ),
41 3b12e641 Leszek Koltunski
    ;
42
43
    final Class<? extends ScrambleEffect> effect;
44
45
    Type(Class<? extends ScrambleEffect> effect)
46
      {
47
      this.effect= effect;
48
      }
49
    }
50
51
  private static int NUM_EFFECTS = Type.values().length;
52
  private static final int FAKE_EFFECT_ID  = -3;
53
  private static final Type[] types;
54
55
  static
56
    {
57
    int i=0;
58
    types = new Type[NUM_EFFECTS];
59
60
    for(Type type: Type.values())
61
      {
62
      types[i++] = type;
63
      }
64
    }
65
66 8becce57 Leszek Koltunski
  private RubikPostRender mPostRender;
67 e8764a49 Leszek Koltunski
  private int mEffectReturned;
68
  private int mNumDoubleScramblesLeft, mNumScramblesLeft;
69
  private int mLastVector;
70
  private long mDurationSingleTurn;
71
  private Random mRnd;
72 27a70eae Leszek Koltunski
  private RubikObject mObject;
73 e844c116 Leszek Koltunski
  private int mNumAxis;
74
  private int mBasicAngle;
75 5cf34c5f Leszek Koltunski
  private float[] mRowChances;
76 3b12e641 Leszek Koltunski
77 e8764a49 Leszek Koltunski
  Effect[] mNodeEffects;
78
  int[] mNodeEffectPosition;
79
  Effect[] mCubeEffects;
80
  int[] mCubeEffectPosition;
81
  int mCubeEffectNumber, mNodeEffectNumber;
82 3b12e641 Leszek Koltunski
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84
85
  ScrambleEffect()
86
    {
87 e8764a49 Leszek Koltunski
    mRnd = new Random( System.currentTimeMillis() );
88 e844c116 Leszek Koltunski
    mLastVector = -2;
89 3b12e641 Leszek Koltunski
    }
90
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92
93 e4db5995 Leszek Koltunski
  abstract void createEffects(int duration, int numScrambles);
94 a62aa9d7 Leszek Koltunski
  abstract void effectFinishedPlugin(final long effectID);
95 3b12e641 Leszek Koltunski
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97 47ba5ddc Leszek Koltunski
// first compute how many out of 'numScrambles' are double turns (this will matter when we compute
98
// the time a single quarter-turn takes!
99 e844c116 Leszek Koltunski
//
100
// Only works for
101 769d7b9f Leszek Koltunski
// basicAngle==4, i.e. something whose rotations are by  90 degrees (RubikCube) or
102 e844c116 Leszek Koltunski
// basicAngle==3, i.e. something whose rotations are by 120 degrees (a Pyramix) or
103 769d7b9f Leszek Koltunski
// basicAngle==2, i.e. something whose rotations are by 180 degrees (e.g. a 3x2x1 'Bunny')
104 e8764a49 Leszek Koltunski
105 a62aa9d7 Leszek Koltunski
  private void createBaseEffects(int duration, int numScrambles)
106 3b12e641 Leszek Koltunski
    {
107 e8764a49 Leszek Koltunski
    mNumScramblesLeft = numScrambles;
108
109
    mNumDoubleScramblesLeft=0;
110
111 e844c116 Leszek Koltunski
    if( mBasicAngle>=4 )
112 e8764a49 Leszek Koltunski
      {
113 e844c116 Leszek Koltunski
      for(int i=0; i<numScrambles; i++)
114 e8764a49 Leszek Koltunski
        {
115 e844c116 Leszek Koltunski
        if( (mRnd.nextInt() % 3) == 0 )
116
          {
117
          mNumDoubleScramblesLeft++;
118
          }
119 e8764a49 Leszek Koltunski
        }
120
      }
121
122
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
123
124
    addNewScramble();
125 a62aa9d7 Leszek Koltunski
    }
126 3b12e641 Leszek Koltunski
127 a62aa9d7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
128 769d7b9f Leszek Koltunski
// only works if basicAngle<=4, i.e. won't work for something whose basic rotations are by less
129 e844c116 Leszek Koltunski
// than 90 degrees.
130 3b12e641 Leszek Koltunski
131 e8764a49 Leszek Koltunski
  private void addNewScramble()
132 a62aa9d7 Leszek Koltunski
    {
133 e8764a49 Leszek Koltunski
    if( mNumScramblesLeft>0 )
134
      {
135 e844c116 Leszek Koltunski
      if( mLastVector == -2 )
136 e8764a49 Leszek Koltunski
        {
137 e844c116 Leszek Koltunski
        mLastVector = mRnd.nextInt(mNumAxis);
138 e8764a49 Leszek Koltunski
        }
139
      else
140
        {
141 e844c116 Leszek Koltunski
        int newVector = mRnd.nextInt(mNumAxis-1);
142
        mLastVector = (newVector>=mLastVector ? newVector+1 : newVector);
143 e8764a49 Leszek Koltunski
        }
144
145 5cf34c5f Leszek Koltunski
      int row=0;
146
      float rowFloat = mRnd.nextFloat();
147
148
      for(int i=0; i<mRowChances.length; i++)
149
        {
150
        if( rowFloat<=mRowChances[i] )
151
          {
152
          row=i;
153
          break;
154
          }
155
        }
156
157
      int rowBitmap  = (1<<row);
158 e8764a49 Leszek Koltunski
      int angle= randomizeAngle();
159
      int absAngle = (angle<0 ? -angle : angle);
160 5cf34c5f Leszek Koltunski
      long durationMillis = absAngle*mDurationSingleTurn;
161 e8764a49 Leszek Koltunski
162
      mNumScramblesLeft--;
163
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
164 3b12e641 Leszek Koltunski
165 2ecf0c21 Leszek Koltunski
      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
166
        {
167
        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
168
        }
169
170 8becce57 Leszek Koltunski
      mPostRender.addRotation(this, mLastVector, rowBitmap, angle*(360/mBasicAngle), durationMillis);
171 e8764a49 Leszek Koltunski
      }
172
    else
173
      {
174
      mLastVector = -1;
175 035fe333 Leszek Koltunski
176
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
177
        {
178 8becce57 Leszek Koltunski
        mPostRender.effectFinished(FAKE_EFFECT_ID);
179 035fe333 Leszek Koltunski
        }
180 e8764a49 Leszek Koltunski
      }
181
    }
182
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184 769d7b9f Leszek Koltunski
// only works for basicAngle<=4.
185 e8764a49 Leszek Koltunski
186
  private int randomizeAngle()
187
    {
188 2ecf0c21 Leszek Koltunski
    int random = mRnd.nextInt(mNumScramblesLeft);
189
    int result = random<mNumDoubleScramblesLeft ? 2:1;
190
    int sign   = mRnd.nextInt(2);
191
192
    return sign==0 ? result : -result;
193 3b12e641 Leszek Koltunski
    }
194
195 47ba5ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
196
197
  private void assignEffects()
198
    {
199
    for(int i=0; i<mCubeEffectNumber; i++)
200
      {
201 27a70eae Leszek Koltunski
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
202 47ba5ddc Leszek Koltunski
      mCubeEffects[i].notifyWhenFinished(this);
203
      }
204
205 27a70eae Leszek Koltunski
    DistortedEffects nodeEffects = mObject.getEffects();
206 47ba5ddc Leszek Koltunski
207
    for(int i=0; i<mNodeEffectNumber; i++)
208
      {
209
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
210
      mNodeEffects[i].notifyWhenFinished(this);
211
      }
212
    }
213
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215
216
  private void disassignEffects()
217
    {
218
    for(int i=0; i<mCubeEffectNumber; i++)
219
      {
220 27a70eae Leszek Koltunski
      mObject.remove(mCubeEffects[i].getID());
221 47ba5ddc Leszek Koltunski
      }
222
223 27a70eae Leszek Koltunski
    DistortedEffects nodeEffects = mObject.getEffects();
224 47ba5ddc Leszek Koltunski
225
    for(int i=0; i<mNodeEffectNumber; i++)
226
      {
227
      nodeEffects.abortById(mNodeEffects[i].getID());
228
      }
229
    }
230
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232
// PUBLIC API
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234
235
  @SuppressWarnings("unused")
236
  public static String[] getNames()
237
    {
238
    String[] names = new String[NUM_EFFECTS];
239
240
    for( int i=0; i<NUM_EFFECTS; i++)
241
      {
242
      names[i] = types[i].name();
243
      }
244
245
    return names;
246
    }
247
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
250
  @SuppressWarnings("unused")
251
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
252
    {
253
    return types[ordinal].effect.newInstance();
254
    }
255
256 3b12e641 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
257
258 8becce57 Leszek Koltunski
  public void onActionFinished(final long effectID)
259 3b12e641 Leszek Koltunski
    {
260 8becce57 Leszek Koltunski
    addNewScramble();
261
    }
262 e8764a49 Leszek Koltunski
263 8becce57 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
264
265
  public void effectFinished(final long effectID)
266
    {
267 e8764a49 Leszek Koltunski
    for(int i=0; i<mCubeEffectNumber; i++)
268 3b12e641 Leszek Koltunski
      {
269 e8764a49 Leszek Koltunski
      long id = mCubeEffects[i].getID();
270
271
      if( effectID == id )
272 a62aa9d7 Leszek Koltunski
        {
273 e8764a49 Leszek Koltunski
        mEffectReturned++;
274
        effectFinishedPlugin(effectID);
275 a62aa9d7 Leszek Koltunski
276 e8764a49 Leszek Koltunski
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
277 a62aa9d7 Leszek Koltunski
          {
278 e8764a49 Leszek Koltunski
          disassignEffects();
279 035fe333 Leszek Koltunski
280
          if( mNumScramblesLeft==0 )
281
            {
282 8becce57 Leszek Koltunski
            mPostRender.effectFinished(FAKE_EFFECT_ID);
283 035fe333 Leszek Koltunski
            }
284 e8764a49 Leszek Koltunski
          }
285 a62aa9d7 Leszek Koltunski
286 e8764a49 Leszek Koltunski
        return;
287
        }
288
      }
289 a62aa9d7 Leszek Koltunski
290 e8764a49 Leszek Koltunski
    for(int i=0; i<mNodeEffectNumber; i++)
291
      {
292
      long id = mNodeEffects[i].getID();
293 a62aa9d7 Leszek Koltunski
294 e8764a49 Leszek Koltunski
      if( effectID == id )
295 a62aa9d7 Leszek Koltunski
        {
296 e8764a49 Leszek Koltunski
        mEffectReturned++;
297
        effectFinishedPlugin(effectID);
298 a62aa9d7 Leszek Koltunski
299 e8764a49 Leszek Koltunski
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
300 a62aa9d7 Leszek Koltunski
          {
301 e8764a49 Leszek Koltunski
          disassignEffects();
302 035fe333 Leszek Koltunski
303
          if( mNumScramblesLeft==0 )
304
            {
305 8becce57 Leszek Koltunski
            mPostRender.effectFinished(FAKE_EFFECT_ID);
306 035fe333 Leszek Koltunski
            }
307 a62aa9d7 Leszek Koltunski
          }
308 e8764a49 Leszek Koltunski
309
        return;
310 a62aa9d7 Leszek Koltunski
        }
311 3b12e641 Leszek Koltunski
      }
312
    }
313
314
///////////////////////////////////////////////////////////////////////////////////////////////////
315
316 47ba5ddc Leszek Koltunski
  @SuppressWarnings("unused")
317 8becce57 Leszek Koltunski
  public long start(int duration, DistortedScreen screen, RubikPostRender post)
318 3b12e641 Leszek Koltunski
    {
319 8becce57 Leszek Koltunski
    mObject     = post.getObject();
320
    mPostRender = post;
321 5cf34c5f Leszek Koltunski
    mRowChances = mObject.getRowChances();
322 a62aa9d7 Leszek Koltunski
323 27a70eae Leszek Koltunski
    mObject.solve();
324 beb325a0 Leszek Koltunski
325 12ad3fca Leszek Koltunski
    mNumAxis    = mObject.getRotationAxis().length;
326 e844c116 Leszek Koltunski
    mBasicAngle = mObject.getBasicAngle();
327
328 8becce57 Leszek Koltunski
    int numScrambles = post.getNumScrambles();
329 e4db5995 Leszek Koltunski
    int dura = (int)(duration*Math.pow(numScrambles,0.6f));
330
    createBaseEffects(dura,numScrambles);
331
    createEffects    (dura,numScrambles);
332 a62aa9d7 Leszek Koltunski
333 e8764a49 Leszek Koltunski
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
334 a62aa9d7 Leszek Koltunski
      {
335
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
336
      }
337
338 e8764a49 Leszek Koltunski
    assignEffects();
339 3b12e641 Leszek Koltunski
340
    return FAKE_EFFECT_ID;
341
    }
342
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344
345
  @SuppressWarnings("unused")
346
  public static void enableEffects()
347
    {
348
    Method method;
349
350
    for(Type type: Type.values())
351
      {
352
      try
353
        {
354
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
355
        }
356
      catch(NoSuchMethodException ex)
357
        {
358
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
359
        method = null;
360
        }
361
362
      try
363
        {
364
        if( method!=null ) method.invoke(null);
365
        }
366
      catch(Exception ex)
367
        {
368
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
369
        }
370
      }
371
    }
372
}