Project

General

Profile

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

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

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 3b12e641 Leszek Koltunski
74 e8764a49 Leszek Koltunski
  Effect[] mNodeEffects;
75
  int[] mNodeEffectPosition;
76
  Effect[] mCubeEffects;
77
  int[] mCubeEffectPosition;
78
  int mCubeEffectNumber, mNodeEffectNumber;
79 3b12e641 Leszek Koltunski
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81
82
  ScrambleEffect()
83
    {
84 e8764a49 Leszek Koltunski
    mRnd = new Random( System.currentTimeMillis() );
85 3c4a326c Leszek Koltunski
    mLastVector = 3;
86 3b12e641 Leszek Koltunski
    }
87
88
///////////////////////////////////////////////////////////////////////////////////////////////////
89
90 e4db5995 Leszek Koltunski
  abstract void createEffects(int duration, int numScrambles);
91 a62aa9d7 Leszek Koltunski
  abstract void effectFinishedPlugin(final long effectID);
92 3b12e641 Leszek Koltunski
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94 47ba5ddc Leszek Koltunski
// first compute how many out of 'numScrambles' are double turns (this will matter when we compute
95
// the time a single quarter-turn takes!
96 e8764a49 Leszek Koltunski
97 a62aa9d7 Leszek Koltunski
  private void createBaseEffects(int duration, int numScrambles)
98 3b12e641 Leszek Koltunski
    {
99 e8764a49 Leszek Koltunski
    mNumScramblesLeft = numScrambles;
100
101
    mNumDoubleScramblesLeft=0;
102
103
    for(int i=0; i<numScrambles; i++)
104
      {
105
      if( (mRnd.nextInt() % 3) == 0 )
106
        {
107
        mNumDoubleScramblesLeft++;
108
        }
109
      }
110
111
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
112
113
    addNewScramble();
114 a62aa9d7 Leszek Koltunski
    }
115 3b12e641 Leszek Koltunski
116 a62aa9d7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
117 3b12e641 Leszek Koltunski
118 e8764a49 Leszek Koltunski
  private void addNewScramble()
119 a62aa9d7 Leszek Koltunski
    {
120 e8764a49 Leszek Koltunski
    if( mNumScramblesLeft>0 )
121
      {
122 3c4a326c Leszek Koltunski
      if( mLastVector == 3 )
123 e8764a49 Leszek Koltunski
        {
124 3c4a326c Leszek Koltunski
        mLastVector = mRnd.nextInt(3);
125 e8764a49 Leszek Koltunski
        }
126
      else
127
        {
128
        int newVector = mRnd.nextInt(2);
129
130
        switch(mLastVector)
131
          {
132 3c4a326c Leszek Koltunski
          case 0: mLastVector = (newVector==0 ? 1:2); break;
133
          case 1: mLastVector = (newVector==0 ? 0:2); break;
134
          case 2: mLastVector = (newVector==0 ? 0:1); break;
135 e8764a49 Leszek Koltunski
          }
136
        }
137
138 27a70eae Leszek Koltunski
      int row  = mRnd.nextInt(mObject.getSize());
139 e8764a49 Leszek Koltunski
      int angle= randomizeAngle();
140
      int absAngle = (angle<0 ? -angle : angle);
141
      long durationMillis =  absAngle*mDurationSingleTurn;
142
143
      mNumScramblesLeft--;
144
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
145 3b12e641 Leszek Koltunski
146 2ecf0c21 Leszek Koltunski
      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
147
        {
148
        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
149
        }
150
151 efef689c Leszek Koltunski
      mCurrentBaseEffectID = mObject.addNewRotation(mLastVector, row, angle*90, durationMillis, this );
152 e8764a49 Leszek Koltunski
      }
153
    else
154
      {
155
      mLastVector = -1;
156 035fe333 Leszek Koltunski
157
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
158
        {
159
        mListener.effectFinished(FAKE_EFFECT_ID);
160
        }
161 e8764a49 Leszek Koltunski
      }
162
    }
163
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165
166
  private int randomizeAngle()
167
    {
168 2ecf0c21 Leszek Koltunski
    int random = mRnd.nextInt(mNumScramblesLeft);
169
    int result = random<mNumDoubleScramblesLeft ? 2:1;
170
    int sign   = mRnd.nextInt(2);
171
172
    return sign==0 ? result : -result;
173 3b12e641 Leszek Koltunski
    }
174
175 47ba5ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
176
177
  private void assignEffects()
178
    {
179
    for(int i=0; i<mCubeEffectNumber; i++)
180
      {
181 27a70eae Leszek Koltunski
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
182 47ba5ddc Leszek Koltunski
      mCubeEffects[i].notifyWhenFinished(this);
183
      }
184
185 27a70eae Leszek Koltunski
    DistortedEffects nodeEffects = mObject.getEffects();
186 47ba5ddc Leszek Koltunski
187
    for(int i=0; i<mNodeEffectNumber; i++)
188
      {
189
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
190
      mNodeEffects[i].notifyWhenFinished(this);
191
      }
192
    }
193
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195
196
  private void disassignEffects()
197
    {
198
    for(int i=0; i<mCubeEffectNumber; i++)
199
      {
200 27a70eae Leszek Koltunski
      mObject.remove(mCubeEffects[i].getID());
201 47ba5ddc Leszek Koltunski
      }
202
203 27a70eae Leszek Koltunski
    DistortedEffects nodeEffects = mObject.getEffects();
204 47ba5ddc Leszek Koltunski
205
    for(int i=0; i<mNodeEffectNumber; i++)
206
      {
207
      nodeEffects.abortById(mNodeEffects[i].getID());
208
      }
209
    }
210
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212
// PUBLIC API
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214
215
  @SuppressWarnings("unused")
216
  public static String[] getNames()
217
    {
218
    String[] names = new String[NUM_EFFECTS];
219
220
    for( int i=0; i<NUM_EFFECTS; i++)
221
      {
222
      names[i] = types[i].name();
223
      }
224
225
    return names;
226
    }
227
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229
230
  @SuppressWarnings("unused")
231
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
232
    {
233
    return types[ordinal].effect.newInstance();
234
    }
235
236 3b12e641 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
237
238 a62aa9d7 Leszek Koltunski
  public void effectFinished(final long effectID)
239 3b12e641 Leszek Koltunski
    {
240 e8764a49 Leszek Koltunski
    if( effectID == mCurrentBaseEffectID )
241
      {
242 27a70eae Leszek Koltunski
      mObject.removeRotationNow();
243 e8764a49 Leszek Koltunski
      addNewScramble();
244
      return;
245
      }
246
247
    for(int i=0; i<mCubeEffectNumber; i++)
248 3b12e641 Leszek Koltunski
      {
249 e8764a49 Leszek Koltunski
      long id = mCubeEffects[i].getID();
250
251
      if( effectID == id )
252 a62aa9d7 Leszek Koltunski
        {
253 e8764a49 Leszek Koltunski
        mEffectReturned++;
254
        effectFinishedPlugin(effectID);
255 a62aa9d7 Leszek Koltunski
256 e8764a49 Leszek Koltunski
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
257 a62aa9d7 Leszek Koltunski
          {
258 e8764a49 Leszek Koltunski
          disassignEffects();
259 035fe333 Leszek Koltunski
260
          if( mNumScramblesLeft==0 )
261
            {
262
            mListener.effectFinished(FAKE_EFFECT_ID);
263
            }
264 e8764a49 Leszek Koltunski
          }
265 a62aa9d7 Leszek Koltunski
266 e8764a49 Leszek Koltunski
        return;
267
        }
268
      }
269 a62aa9d7 Leszek Koltunski
270 e8764a49 Leszek Koltunski
    for(int i=0; i<mNodeEffectNumber; i++)
271
      {
272
      long id = mNodeEffects[i].getID();
273 a62aa9d7 Leszek Koltunski
274 e8764a49 Leszek Koltunski
      if( effectID == id )
275 a62aa9d7 Leszek Koltunski
        {
276 e8764a49 Leszek Koltunski
        mEffectReturned++;
277
        effectFinishedPlugin(effectID);
278 a62aa9d7 Leszek Koltunski
279 e8764a49 Leszek Koltunski
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
280 a62aa9d7 Leszek Koltunski
          {
281 e8764a49 Leszek Koltunski
          disassignEffects();
282 035fe333 Leszek Koltunski
283
          if( mNumScramblesLeft==0 )
284
            {
285
            mListener.effectFinished(FAKE_EFFECT_ID);
286
            }
287 a62aa9d7 Leszek Koltunski
          }
288 e8764a49 Leszek Koltunski
289
        return;
290 a62aa9d7 Leszek Koltunski
        }
291 3b12e641 Leszek Koltunski
      }
292
    }
293
294
///////////////////////////////////////////////////////////////////////////////////////////////////
295
296 47ba5ddc Leszek Koltunski
  @SuppressWarnings("unused")
297 64975793 Leszek Koltunski
  public long start(int duration, RubikRenderer renderer)
298 3b12e641 Leszek Koltunski
    {
299 27a70eae Leszek Koltunski
    mObject   = renderer.getObject();
300 64975793 Leszek Koltunski
    mListener = renderer;
301 a62aa9d7 Leszek Koltunski
302 27a70eae Leszek Koltunski
    mObject.solve();
303 beb325a0 Leszek Koltunski
304 64975793 Leszek Koltunski
    int numScrambles = renderer.getNumScrambles();
305 e4db5995 Leszek Koltunski
    int dura = (int)(duration*Math.pow(numScrambles,0.6f));
306
    createBaseEffects(dura,numScrambles);
307
    createEffects    (dura,numScrambles);
308 a62aa9d7 Leszek Koltunski
309 e8764a49 Leszek Koltunski
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
310 a62aa9d7 Leszek Koltunski
      {
311
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
312
      }
313
314 e8764a49 Leszek Koltunski
    assignEffects();
315 3b12e641 Leszek Koltunski
316
    return FAKE_EFFECT_ID;
317
    }
318
319
///////////////////////////////////////////////////////////////////////////////////////////////////
320
321
  @SuppressWarnings("unused")
322
  public static void enableEffects()
323
    {
324
    Method method;
325
326
    for(Type type: Type.values())
327
      {
328
      try
329
        {
330
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
331
        }
332
      catch(NoSuchMethodException ex)
333
        {
334
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
335
        method = null;
336
        }
337
338
      try
339
        {
340
        if( method!=null ) method.invoke(null);
341
        }
342
      catch(Exception ex)
343
        {
344
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
345
        }
346
      }
347
    }
348
}