Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// 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
// Distorted is distributed in the hope that it will be useful,                                  //
12
// 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
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.effect.scramble;
21

    
22
import org.distorted.effect.BaseEffect;
23
import org.distorted.library.effect.Effect;
24
import org.distorted.library.main.DistortedEffects;
25
import org.distorted.library.message.EffectListener;
26
import org.distorted.magic.RubikCube;
27
import org.distorted.magic.RubikRenderer;
28

    
29
import java.lang.reflect.Method;
30
import java.util.Random;
31

    
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33

    
34
public abstract class ScrambleEffect extends BaseEffect implements EffectListener
35
{
36
  public enum Type
37
    {
38
    NONE         (ScrambleEffectNone.class        ),
39
    ROTATIONS    (ScrambleEffectRotations.class   ),
40
    ;
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
  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
  private RubikCube mCube;
73

    
74
  Effect[] mNodeEffects;
75
  int[] mNodeEffectPosition;
76
  Effect[] mCubeEffects;
77
  int[] mCubeEffectPosition;
78
  int mCubeEffectNumber, mNodeEffectNumber;
79

    
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81

    
82
  ScrambleEffect()
83
    {
84
    mRnd = new Random( System.currentTimeMillis() );
85
    mLastVector = -1;
86
    }
87

    
88
///////////////////////////////////////////////////////////////////////////////////////////////////
89

    
90
  abstract void createEffects(int duration);
91
  abstract void effectFinishedPlugin(final long effectID);
92

    
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94
// 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

    
97
  private void createBaseEffects(int duration, int numScrambles)
98
    {
99
    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
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117

    
118
  private void addNewScramble()
119
    {
120
    if( mNumScramblesLeft>0 )
121
      {
122
      if( mLastVector == -1 )
123
        {
124
        switch(mRnd.nextInt(3))
125
          {
126
          case 0: mLastVector = RubikCube.VECTX; break;
127
          case 1: mLastVector = RubikCube.VECTY; break;
128
          case 2: mLastVector = RubikCube.VECTZ; break;
129
          }
130
        }
131
      else
132
        {
133
        int newVector = mRnd.nextInt(2);
134

    
135
        switch(mLastVector)
136
          {
137
          case RubikCube.VECTX: mLastVector = (newVector==0 ? RubikCube.VECTY: RubikCube.VECTZ); break;
138
          case RubikCube.VECTY: mLastVector = (newVector==0 ? RubikCube.VECTX: RubikCube.VECTZ); break;
139
          case RubikCube.VECTZ: mLastVector = (newVector==0 ? RubikCube.VECTX: RubikCube.VECTY); break;
140
          }
141
        }
142

    
143
      int row  = mRnd.nextInt(mCube.getSize());
144
      int angle= randomizeAngle();
145
      int absAngle = (angle<0 ? -angle : angle);
146
      long durationMillis =  absAngle*mDurationSingleTurn;
147

    
148
      mNumScramblesLeft--;
149
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
150

    
151
      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
152
        {
153
        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
154
        }
155

    
156
      mCurrentBaseEffectID = mCube.addNewRotation(mLastVector, row, angle*90, durationMillis, this );
157
      }
158
    else
159
      {
160
      mLastVector = -1;
161

    
162
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
163
        {
164
        mListener.effectFinished(FAKE_EFFECT_ID);
165
        }
166
      }
167
    }
168

    
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170

    
171
  private int randomizeAngle()
172
    {
173
    int random = mRnd.nextInt(mNumScramblesLeft);
174
    int result = random<mNumDoubleScramblesLeft ? 2:1;
175
    int sign   = mRnd.nextInt(2);
176

    
177
    return sign==0 ? result : -result;
178
    }
179

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

    
182
  private void assignEffects()
183
    {
184
    for(int i=0; i<mCubeEffectNumber; i++)
185
      {
186
      mCube.apply(mCubeEffects[i],mCubeEffectPosition[i]);
187
      mCubeEffects[i].notifyWhenFinished(this);
188
      }
189

    
190
    DistortedEffects nodeEffects = mCube.getEffects();
191

    
192
    for(int i=0; i<mNodeEffectNumber; i++)
193
      {
194
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
195
      mNodeEffects[i].notifyWhenFinished(this);
196
      }
197
    }
198

    
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

    
201
  private void disassignEffects()
202
    {
203
    for(int i=0; i<mCubeEffectNumber; i++)
204
      {
205
      mCube.remove(mCubeEffects[i].getID());
206
      }
207

    
208
    DistortedEffects nodeEffects = mCube.getEffects();
209

    
210
    for(int i=0; i<mNodeEffectNumber; i++)
211
      {
212
      nodeEffects.abortById(mNodeEffects[i].getID());
213
      }
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217
// PUBLIC API
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219

    
220
  @SuppressWarnings("unused")
221
  public static String[] getNames()
222
    {
223
    String[] names = new String[NUM_EFFECTS];
224

    
225
    for( int i=0; i<NUM_EFFECTS; i++)
226
      {
227
      names[i] = types[i].name();
228
      }
229

    
230
    return names;
231
    }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

    
235
  @SuppressWarnings("unused")
236
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
237
    {
238
    return types[ordinal].effect.newInstance();
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  public void effectFinished(final long effectID)
244
    {
245
    if( effectID == mCurrentBaseEffectID )
246
      {
247
      mCube.removeRotationNow();
248
      addNewScramble();
249
      return;
250
      }
251

    
252
    for(int i=0; i<mCubeEffectNumber; i++)
253
      {
254
      long id = mCubeEffects[i].getID();
255

    
256
      if( effectID == id )
257
        {
258
        mEffectReturned++;
259
        effectFinishedPlugin(effectID);
260

    
261
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
262
          {
263
          disassignEffects();
264

    
265
          if( mNumScramblesLeft==0 )
266
            {
267
            mListener.effectFinished(FAKE_EFFECT_ID);
268
            }
269
          }
270

    
271
        return;
272
        }
273
      }
274

    
275
    for(int i=0; i<mNodeEffectNumber; i++)
276
      {
277
      long id = mNodeEffects[i].getID();
278

    
279
      if( effectID == id )
280
        {
281
        mEffectReturned++;
282
        effectFinishedPlugin(effectID);
283

    
284
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
285
          {
286
          disassignEffects();
287

    
288
          if( mNumScramblesLeft==0 )
289
            {
290
            mListener.effectFinished(FAKE_EFFECT_ID);
291
            }
292
          }
293

    
294
        return;
295
        }
296
      }
297
    }
298

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300

    
301
  @SuppressWarnings("unused")
302
  public long start(int duration, RubikRenderer renderer)
303
    {
304
    mCube     = renderer.getCube();
305
    mListener = renderer;
306

    
307
    int numScrambles = renderer.getNumScrambles();
308

    
309
    createBaseEffects(numScrambles*duration, numScrambles);
310
    createEffects(numScrambles*duration);
311

    
312
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
313
      {
314
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
315
      }
316

    
317
    assignEffects();
318

    
319
    return FAKE_EFFECT_ID;
320
    }
321

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323

    
324
  @SuppressWarnings("unused")
325
  public static void enableEffects()
326
    {
327
    Method method;
328

    
329
    for(Type type: Type.values())
330
      {
331
      try
332
        {
333
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
334
        }
335
      catch(NoSuchMethodException ex)
336
        {
337
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
338
        method = null;
339
        }
340

    
341
      try
342
        {
343
        if( method!=null ) method.invoke(null);
344
        }
345
      catch(Exception ex)
346
        {
347
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
348
        }
349
      }
350
    }
351
}
(1-1/3)