Project

General

Profile

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

magiccube / src / main / java / org / distorted / effect / scramble / ScrambleEffect.java @ 9224ffd2

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