Project

General

Profile

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

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

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
  public static String[] getNames()
91
    {
92
    String[] names = new String[NUM_EFFECTS];
93

    
94
    for( int i=0; i<NUM_EFFECTS; i++)
95
      {
96
      names[i] = types[i].name();
97
      }
98

    
99
    return names;
100
    }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
105
    {
106
    return types[ordinal].effect.newInstance();
107
    }
108

    
109
///////////////////////////////////////////////////////////////////////////////////////////////////
110

    
111
  abstract void createEffects(int duration);
112
  abstract void effectFinishedPlugin(final long effectID);
113

    
114
///////////////////////////////////////////////////////////////////////////////////////////////////
115

    
116
  private void createBaseEffects(int duration, int numScrambles)
117
    {
118
    mNumScramblesLeft = numScrambles;
119

    
120
    // compute how many out of 'numScrambles' are double turns.
121
    mNumDoubleScramblesLeft=0;
122

    
123
    for(int i=0; i<numScrambles; i++)
124
      {
125
      if( (mRnd.nextInt() % 3) == 0 )
126
        {
127
        mNumDoubleScramblesLeft++;
128
        }
129
      }
130

    
131
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
132

    
133
    addNewScramble();
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

    
138
  private void addNewScramble()
139
    {
140
    if( mNumScramblesLeft>0 )
141
      {
142
      if( mLastVector == -1 )
143
        {
144
        switch(mRnd.nextInt(3))
145
          {
146
          case 0: mLastVector = RubikCube.VECTX; break;
147
          case 1: mLastVector = RubikCube.VECTY; break;
148
          case 2: mLastVector = RubikCube.VECTZ; break;
149
          }
150
        }
151
      else
152
        {
153
        int newVector = mRnd.nextInt(2);
154

    
155
        switch(mLastVector)
156
          {
157
          case RubikCube.VECTX: mLastVector = (newVector==0 ? RubikCube.VECTY: RubikCube.VECTZ); break;
158
          case RubikCube.VECTY: mLastVector = (newVector==0 ? RubikCube.VECTX: RubikCube.VECTZ); break;
159
          case RubikCube.VECTZ: mLastVector = (newVector==0 ? RubikCube.VECTX: RubikCube.VECTY); break;
160
          }
161
        }
162

    
163
      int row  = mRnd.nextInt(mCube.getSize());
164
      int angle= randomizeAngle();
165
      int absAngle = (angle<0 ? -angle : angle);
166
      long durationMillis =  absAngle*mDurationSingleTurn;
167

    
168
      mNumScramblesLeft--;
169
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
170

    
171
      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
172
        {
173
        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
174
        }
175

    
176
      mCurrentBaseEffectID = mCube.addNewRotation(mLastVector, row, angle*90, durationMillis, this );
177
      }
178
    else
179
      {
180
      mLastVector = -1;
181

    
182
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
183
        {
184
        mListener.effectFinished(FAKE_EFFECT_ID);
185
        }
186
      }
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
  private int randomizeAngle()
192
    {
193
    int random = mRnd.nextInt(mNumScramblesLeft);
194
    int result = random<mNumDoubleScramblesLeft ? 2:1;
195
    int sign   = mRnd.nextInt(2);
196

    
197
    return sign==0 ? result : -result;
198
    }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

    
202
  public void effectFinished(final long effectID)
203
    {
204
    if( effectID == mCurrentBaseEffectID )
205
      {
206
      mCube.removeRotationNow();
207
      addNewScramble();
208
      return;
209
      }
210

    
211
    for(int i=0; i<mCubeEffectNumber; i++)
212
      {
213
      long id = mCubeEffects[i].getID();
214

    
215
      if( effectID == id )
216
        {
217
        mEffectReturned++;
218
        effectFinishedPlugin(effectID);
219

    
220
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
221
          {
222
          disassignEffects();
223

    
224
          if( mNumScramblesLeft==0 )
225
            {
226
            mListener.effectFinished(FAKE_EFFECT_ID);
227
            }
228
          }
229

    
230
        return;
231
        }
232
      }
233

    
234
    for(int i=0; i<mNodeEffectNumber; i++)
235
      {
236
      long id = mNodeEffects[i].getID();
237

    
238
      if( effectID == id )
239
        {
240
        mEffectReturned++;
241
        effectFinishedPlugin(effectID);
242

    
243
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
244
          {
245
          disassignEffects();
246

    
247
          if( mNumScramblesLeft==0 )
248
            {
249
            mListener.effectFinished(FAKE_EFFECT_ID);
250
            }
251
          }
252

    
253
        return;
254
        }
255
      }
256
    }
257

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

    
260
  public long start(int duration, RubikRenderer renderer)
261
    {
262
    mCube     = renderer.getCube();
263
    mListener = renderer;
264

    
265
    int numScrambles = renderer.getNumScrambles();
266

    
267
    createBaseEffects(numScrambles*duration, numScrambles);
268
    createEffects(numScrambles*duration);
269

    
270
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
271
      {
272
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
273
      }
274

    
275
    assignEffects();
276

    
277
    return FAKE_EFFECT_ID;
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  private void assignEffects()
283
    {
284
    for(int i=0; i<mCubeEffectNumber; i++)
285
      {
286
      mCube.apply(mCubeEffects[i],mCubeEffectPosition[i]);
287
      mCubeEffects[i].notifyWhenFinished(this);
288
      }
289

    
290
    DistortedEffects nodeEffects = mCube.getEffects();
291

    
292
    for(int i=0; i<mNodeEffectNumber; i++)
293
      {
294
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
295
      mNodeEffects[i].notifyWhenFinished(this);
296
      }
297
    }
298

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

    
301
  private void disassignEffects()
302
    {
303
    for(int i=0; i<mCubeEffectNumber; i++)
304
      {
305
      mCube.remove(mCubeEffects[i].getID());
306
      }
307

    
308
    DistortedEffects nodeEffects = mCube.getEffects();
309

    
310
    for(int i=0; i<mNodeEffectNumber; i++)
311
      {
312
      nodeEffects.abortById(mNodeEffects[i].getID());
313
      }
314
    }
315

    
316
///////////////////////////////////////////////////////////////////////////////////////////////////
317

    
318
  @SuppressWarnings("unused")
319
  public static void enableEffects()
320
    {
321
    Method method;
322

    
323
    for(Type type: Type.values())
324
      {
325
      try
326
        {
327
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
328
        }
329
      catch(NoSuchMethodException ex)
330
        {
331
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
332
        method = null;
333
        }
334

    
335
      try
336
        {
337
        if( method!=null ) method.invoke(null);
338
        }
339
      catch(Exception ex)
340
        {
341
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
342
        }
343
      }
344
    }
345
}
(1-1/3)