Project

General

Profile

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

magiccube / src / main / java / org / distorted / effect / ScrambleEffect.java @ 42772cff

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;
21

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

    
27
import java.lang.reflect.Method;
28
import java.util.Random;
29

    
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31

    
32
public abstract class ScrambleEffect implements EffectListener
33
{
34
  public enum Type
35
    {
36
    NONE         (ScrambleEffectNone.class        ),
37
    ROTATIONS    (ScrambleEffectRotations.class   ),
38
    ;
39

    
40
    final Class<? extends ScrambleEffect> effect;
41

    
42
    Type(Class<? extends ScrambleEffect> effect)
43
      {
44
      this.effect= effect;
45
      }
46
    }
47

    
48
  private static int NUM_EFFECTS = Type.values().length;
49
  private static final int FAKE_EFFECT_ID  = -3;
50
  private static final Type[] types;
51

    
52
  static
53
    {
54
    int i=0;
55
    types = new Type[NUM_EFFECTS];
56

    
57
    for(Type type: Type.values())
58
      {
59
      types[i++] = type;
60
      }
61
    }
62

    
63
  private EffectListener mListener;
64
  private int mEffectReturned;
65
  private long mCurrentBaseEffectID;
66
  private int mNumDoubleScramblesLeft, mNumScramblesLeft;
67
  private int mLastVector;
68
  private long mDurationSingleTurn;
69
  private Random mRnd;
70
  private RubikCube mCube;
71

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

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

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

    
86
///////////////////////////////////////////////////////////////////////////////////////////////////
87

    
88
  public static String[] getNames()
89
    {
90
    String[] names = new String[NUM_EFFECTS];
91

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

    
97
    return names;
98
    }
99

    
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101

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

    
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108

    
109
  abstract void createEffects(int duration);
110
  abstract void effectFinishedPlugin(final long effectID);
111

    
112
///////////////////////////////////////////////////////////////////////////////////////////////////
113

    
114
  private void createBaseEffects(int duration, int numScrambles)
115
    {
116
    mNumScramblesLeft = numScrambles;
117

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

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

    
129
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
130

    
131
    addNewScramble();
132
    }
133

    
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135

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

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

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

    
166
      mNumScramblesLeft--;
167
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
168

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

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

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

    
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188

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

    
195
    return sign==0 ? result : -result;
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

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

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

    
213
      if( effectID == id )
214
        {
215
        mEffectReturned++;
216
        effectFinishedPlugin(effectID);
217

    
218
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
219
          {
220
          disassignEffects();
221

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

    
228
        return;
229
        }
230
      }
231

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

    
236
      if( effectID == id )
237
        {
238
        mEffectReturned++;
239
        effectFinishedPlugin(effectID);
240

    
241
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
242
          {
243
          disassignEffects();
244

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

    
251
        return;
252
        }
253
      }
254
    }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257

    
258
  public long start(int duration, RubikCube cube, int numScrambles, EffectListener listener)
259
    {
260
    mCube     = cube;
261
    mListener = listener;
262

    
263
    createBaseEffects(duration, numScrambles);
264
    createEffects(duration);
265

    
266
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
267
      {
268
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
269
      }
270

    
271
    assignEffects();
272

    
273
    return FAKE_EFFECT_ID;
274
    }
275

    
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

    
278
  private void assignEffects()
279
    {
280
    for(int i=0; i<mCubeEffectNumber; i++)
281
      {
282
      mCube.apply(mCubeEffects[i],mCubeEffectPosition[i]);
283
      mCubeEffects[i].notifyWhenFinished(this);
284
      }
285

    
286
    DistortedEffects nodeEffects = mCube.getEffects();
287

    
288
    for(int i=0; i<mNodeEffectNumber; i++)
289
      {
290
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
291
      mNodeEffects[i].notifyWhenFinished(this);
292
      }
293
    }
294

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296

    
297
  private void disassignEffects()
298
    {
299
    for(int i=0; i<mCubeEffectNumber; i++)
300
      {
301
      mCube.remove(mCubeEffects[i].getID());
302
      }
303

    
304
    DistortedEffects nodeEffects = mCube.getEffects();
305

    
306
    for(int i=0; i<mNodeEffectNumber; i++)
307
      {
308
      nodeEffects.abortById(mNodeEffects[i].getID());
309
      }
310
    }
311

    
312
///////////////////////////////////////////////////////////////////////////////////////////////////
313

    
314
  @SuppressWarnings("unused")
315
  public static void enableEffects()
316
    {
317
    Method method;
318

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

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