Project

General

Profile

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

magiccube / src / main / java / org / distorted / effects / scramble / ScrambleEffect.java @ 36b9ee93

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 5a4d4fba Leszek Koltunski
import org.distorted.main.RubikPreRender;
28 af88bf2e Leszek Koltunski
import org.distorted.effects.EffectController;
29 9c2f0c91 Leszek Koltunski
import org.distorted.objects.TwistyObject;
30 3b12e641 Leszek Koltunski
31
import java.lang.reflect.Method;
32 e8764a49 Leszek Koltunski
import java.util.Random;
33 3b12e641 Leszek Koltunski
34
///////////////////////////////////////////////////////////////////////////////////////////////////
35
36 5a4d4fba Leszek Koltunski
public abstract class ScrambleEffect extends BaseEffect implements EffectListener, RubikPreRender.ActionFinishedListener
37 3b12e641 Leszek Koltunski
{
38
  public enum Type
39
    {
40
    NONE         (ScrambleEffectNone.class        ),
41 a62aa9d7 Leszek Koltunski
    ROTATIONS    (ScrambleEffectRotations.class   ),
42 3b12e641 Leszek Koltunski
    ;
43
44
    final Class<? extends ScrambleEffect> effect;
45
46
    Type(Class<? extends ScrambleEffect> effect)
47
      {
48
      this.effect= effect;
49
      }
50
    }
51
52 36b9ee93 Leszek Koltunski
  private static final int NUM_EFFECTS = Type.values().length;
53 3b12e641 Leszek Koltunski
  private static final int FAKE_EFFECT_ID  = -3;
54
  private static final Type[] types;
55
56
  static
57
    {
58
    int i=0;
59
    types = new Type[NUM_EFFECTS];
60
61
    for(Type type: Type.values())
62
      {
63
      types[i++] = type;
64
      }
65
    }
66
67 7c969a6d Leszek Koltunski
  public static final int START_AXIS = -2;
68
  public static final int STOP_AXIS  = -1;
69
70 af88bf2e Leszek Koltunski
  private EffectController mController;
71 e8764a49 Leszek Koltunski
  private int mEffectReturned;
72
  private int mNumDoubleScramblesLeft, mNumScramblesLeft;
73 7c969a6d Leszek Koltunski
  private int mLastRotAxis, mLastRow;
74 e8764a49 Leszek Koltunski
  private long mDurationSingleTurn;
75 36b9ee93 Leszek Koltunski
  private final Random mRnd;
76 e844c116 Leszek Koltunski
  private int mBasicAngle;
77 3b12e641 Leszek Koltunski
78 9c2f0c91 Leszek Koltunski
  TwistyObject mObject;
79 e8764a49 Leszek Koltunski
  Effect[] mNodeEffects;
80
  int[] mNodeEffectPosition;
81
  Effect[] mCubeEffects;
82
  int[] mCubeEffectPosition;
83
  int mCubeEffectNumber, mNodeEffectNumber;
84 3b12e641 Leszek Koltunski
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86
87
  ScrambleEffect()
88
    {
89 e8764a49 Leszek Koltunski
    mRnd = new Random( System.currentTimeMillis() );
90 7c969a6d Leszek Koltunski
    mLastRotAxis = START_AXIS;
91 3b12e641 Leszek Koltunski
    }
92
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94
95 e4db5995 Leszek Koltunski
  abstract void createEffects(int duration, int numScrambles);
96 a62aa9d7 Leszek Koltunski
  abstract void effectFinishedPlugin(final long effectID);
97 3b12e641 Leszek Koltunski
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99 47ba5ddc Leszek Koltunski
// first compute how many out of 'numScrambles' are double turns (this will matter when we compute
100
// the time a single quarter-turn takes!
101 e844c116 Leszek Koltunski
//
102
// Only works for
103 7c969a6d Leszek Koltunski
// basicAngle==5, i.e. something whose rotations are by  72 degrees (Megaminx) or
104 769d7b9f Leszek Koltunski
// basicAngle==4, i.e. something whose rotations are by  90 degrees (RubikCube) or
105 7c969a6d Leszek Koltunski
// basicAngle==3, i.e. something whose rotations are by 120 degrees (Pyramix) or
106 769d7b9f Leszek Koltunski
// basicAngle==2, i.e. something whose rotations are by 180 degrees (e.g. a 3x2x1 'Bunny')
107 e8764a49 Leszek Koltunski
108 a62aa9d7 Leszek Koltunski
  private void createBaseEffects(int duration, int numScrambles)
109 3b12e641 Leszek Koltunski
    {
110 e8764a49 Leszek Koltunski
    mNumScramblesLeft = numScrambles;
111
112
    mNumDoubleScramblesLeft=0;
113
114 e844c116 Leszek Koltunski
    if( mBasicAngle>=4 )
115 e8764a49 Leszek Koltunski
      {
116 7c969a6d Leszek Koltunski
      int chance = mBasicAngle==4 ? 3:2;
117
118 e844c116 Leszek Koltunski
      for(int i=0; i<numScrambles; i++)
119 e8764a49 Leszek Koltunski
        {
120 7c969a6d Leszek Koltunski
        if( (mRnd.nextInt() % chance) == 0 )
121 e844c116 Leszek Koltunski
          {
122
          mNumDoubleScramblesLeft++;
123
          }
124 e8764a49 Leszek Koltunski
        }
125
      }
126
127
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
128
129
    addNewScramble();
130 a62aa9d7 Leszek Koltunski
    }
131 3b12e641 Leszek Koltunski
132 a62aa9d7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
133 7c969a6d Leszek Koltunski
// only works if basicAngle<=5
134 3b12e641 Leszek Koltunski
135 e8764a49 Leszek Koltunski
  private void addNewScramble()
136 a62aa9d7 Leszek Koltunski
    {
137 e8764a49 Leszek Koltunski
    if( mNumScramblesLeft>0 )
138
      {
139 7c969a6d Leszek Koltunski
      int lastRotAxis = mLastRotAxis;
140
      mLastRotAxis = mObject.randomizeNewRotAxis(mRnd,mLastRotAxis);
141
      mLastRow = mObject.randomizeNewRow(mRnd,lastRotAxis,mLastRow,mLastRotAxis);
142 5cf34c5f Leszek Koltunski
143 7c969a6d Leszek Koltunski
      int rowBitmap  = (1<<mLastRow);
144 e8764a49 Leszek Koltunski
      int angle= randomizeAngle();
145
      int absAngle = (angle<0 ? -angle : angle);
146 5cf34c5f Leszek Koltunski
      long durationMillis = absAngle*mDurationSingleTurn;
147 e8764a49 Leszek Koltunski
148
      mNumScramblesLeft--;
149
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
150 3b12e641 Leszek Koltunski
151 2ecf0c21 Leszek Koltunski
      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
152
        {
153
        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
154
        }
155
156 af88bf2e Leszek Koltunski
      mController.addRotation(this, mLastRotAxis, rowBitmap, angle*(360/mBasicAngle), durationMillis);
157 e8764a49 Leszek Koltunski
      }
158
    else
159
      {
160 7c969a6d Leszek Koltunski
      mLastRotAxis = STOP_AXIS;
161 035fe333 Leszek Koltunski
162
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
163
        {
164 af88bf2e Leszek Koltunski
        mController.effectFinished(FAKE_EFFECT_ID);
165 035fe333 Leszek Koltunski
        }
166 e8764a49 Leszek Koltunski
      }
167
    }
168
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170 7c969a6d Leszek Koltunski
// only works for basicAngle<=5.
171 e8764a49 Leszek Koltunski
172
  private int randomizeAngle()
173
    {
174 2ecf0c21 Leszek Koltunski
    int random = mRnd.nextInt(mNumScramblesLeft);
175
    int result = random<mNumDoubleScramblesLeft ? 2:1;
176
    int sign   = mRnd.nextInt(2);
177
178
    return sign==0 ? result : -result;
179 3b12e641 Leszek Koltunski
    }
180
181 47ba5ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
182
183
  private void assignEffects()
184
    {
185
    for(int i=0; i<mCubeEffectNumber; i++)
186
      {
187 27a70eae Leszek Koltunski
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
188 47ba5ddc Leszek Koltunski
      mCubeEffects[i].notifyWhenFinished(this);
189
      }
190
191 27a70eae Leszek Koltunski
    DistortedEffects nodeEffects = mObject.getEffects();
192 47ba5ddc Leszek Koltunski
193
    for(int i=0; i<mNodeEffectNumber; i++)
194
      {
195
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
196
      mNodeEffects[i].notifyWhenFinished(this);
197
      }
198
    }
199
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201
202
  private void disassignEffects()
203
    {
204
    for(int i=0; i<mCubeEffectNumber; i++)
205
      {
206 27a70eae Leszek Koltunski
      mObject.remove(mCubeEffects[i].getID());
207 47ba5ddc Leszek Koltunski
      }
208
209 27a70eae Leszek Koltunski
    DistortedEffects nodeEffects = mObject.getEffects();
210 47ba5ddc Leszek Koltunski
211
    for(int i=0; i<mNodeEffectNumber; i++)
212
      {
213
      nodeEffects.abortById(mNodeEffects[i].getID());
214
      }
215
    }
216
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218
// PUBLIC API
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220
221
  @SuppressWarnings("unused")
222
  public static String[] getNames()
223
    {
224
    String[] names = new String[NUM_EFFECTS];
225
226
    for( int i=0; i<NUM_EFFECTS; i++)
227
      {
228
      names[i] = types[i].name();
229
      }
230
231
    return names;
232
    }
233
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235
236
  @SuppressWarnings("unused")
237
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
238
    {
239
    return types[ordinal].effect.newInstance();
240
    }
241
242 3b12e641 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
243
244 8becce57 Leszek Koltunski
  public void onActionFinished(final long effectID)
245 3b12e641 Leszek Koltunski
    {
246 8becce57 Leszek Koltunski
    addNewScramble();
247
    }
248 e8764a49 Leszek Koltunski
249 8becce57 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
250
251
  public void effectFinished(final long effectID)
252
    {
253 e8764a49 Leszek Koltunski
    for(int i=0; i<mCubeEffectNumber; i++)
254 3b12e641 Leszek Koltunski
      {
255 e8764a49 Leszek Koltunski
      long id = mCubeEffects[i].getID();
256
257
      if( effectID == id )
258 a62aa9d7 Leszek Koltunski
        {
259 e8764a49 Leszek Koltunski
        mEffectReturned++;
260
        effectFinishedPlugin(effectID);
261 a62aa9d7 Leszek Koltunski
262 e8764a49 Leszek Koltunski
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
263 a62aa9d7 Leszek Koltunski
          {
264 e8764a49 Leszek Koltunski
          disassignEffects();
265 035fe333 Leszek Koltunski
266
          if( mNumScramblesLeft==0 )
267
            {
268 af88bf2e Leszek Koltunski
            mController.effectFinished(FAKE_EFFECT_ID);
269 035fe333 Leszek Koltunski
            }
270 e8764a49 Leszek Koltunski
          }
271 a62aa9d7 Leszek Koltunski
272 e8764a49 Leszek Koltunski
        return;
273
        }
274
      }
275 a62aa9d7 Leszek Koltunski
276 e8764a49 Leszek Koltunski
    for(int i=0; i<mNodeEffectNumber; i++)
277
      {
278
      long id = mNodeEffects[i].getID();
279 a62aa9d7 Leszek Koltunski
280 e8764a49 Leszek Koltunski
      if( effectID == id )
281 a62aa9d7 Leszek Koltunski
        {
282 e8764a49 Leszek Koltunski
        mEffectReturned++;
283
        effectFinishedPlugin(effectID);
284 a62aa9d7 Leszek Koltunski
285 e8764a49 Leszek Koltunski
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
286 a62aa9d7 Leszek Koltunski
          {
287 e8764a49 Leszek Koltunski
          disassignEffects();
288 035fe333 Leszek Koltunski
289
          if( mNumScramblesLeft==0 )
290
            {
291 af88bf2e Leszek Koltunski
            mController.effectFinished(FAKE_EFFECT_ID);
292 035fe333 Leszek Koltunski
            }
293 a62aa9d7 Leszek Koltunski
          }
294 e8764a49 Leszek Koltunski
295
        return;
296 a62aa9d7 Leszek Koltunski
        }
297 3b12e641 Leszek Koltunski
      }
298
    }
299
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301
302 47ba5ddc Leszek Koltunski
  @SuppressWarnings("unused")
303 af88bf2e Leszek Koltunski
  public long start(int duration, DistortedScreen screen, EffectController cont)
304 3b12e641 Leszek Koltunski
    {
305 af88bf2e Leszek Koltunski
    mObject    = cont.getObject();
306
    mController= cont;
307 a62aa9d7 Leszek Koltunski
308 27a70eae Leszek Koltunski
    mObject.solve();
309 beb325a0 Leszek Koltunski
310 e844c116 Leszek Koltunski
    mBasicAngle = mObject.getBasicAngle();
311
312 af88bf2e Leszek Koltunski
    int numScrambles = cont.getNumScrambles();
313 e4db5995 Leszek Koltunski
    int dura = (int)(duration*Math.pow(numScrambles,0.6f));
314
    createBaseEffects(dura,numScrambles);
315
    createEffects    (dura,numScrambles);
316 a62aa9d7 Leszek Koltunski
317 e8764a49 Leszek Koltunski
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
318 a62aa9d7 Leszek Koltunski
      {
319
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
320
      }
321
322 e8764a49 Leszek Koltunski
    assignEffects();
323 3b12e641 Leszek Koltunski
324
    return FAKE_EFFECT_ID;
325
    }
326
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328
329
  @SuppressWarnings("unused")
330
  public static void enableEffects()
331
    {
332
    Method method;
333
334
    for(Type type: Type.values())
335
      {
336
      try
337
        {
338
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
339
        }
340
      catch(NoSuchMethodException ex)
341
        {
342
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
343
        method = null;
344
        }
345
346
      try
347
        {
348
        if( method!=null ) method.invoke(null);
349
        }
350
      catch(Exception ex)
351
        {
352
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
353
        }
354
      }
355
    }
356
}