Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube 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
// Magic Cube 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 Magic Cube.  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.library.type.Static3D;
27
import org.distorted.magic.RubikRenderer;
28
import org.distorted.object.RubikObject;
29

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

    
33
///////////////////////////////////////////////////////////////////////////////////////////////////
34

    
35
public abstract class ScrambleEffect extends BaseEffect implements EffectListener
36
{
37
  public enum Type
38
    {
39
    NONE         (ScrambleEffectNone.class        ),
40
    ROTATIONS    (ScrambleEffectRotations.class   ),
41
    ;
42

    
43
    final Class<? extends ScrambleEffect> effect;
44

    
45
    Type(Class<? extends ScrambleEffect> effect)
46
      {
47
      this.effect= effect;
48
      }
49
    }
50

    
51
  private static int NUM_EFFECTS = Type.values().length;
52
  private static final int FAKE_EFFECT_ID  = -3;
53
  private static final Type[] types;
54

    
55
  private static final Static3D VECTX = new Static3D(1,0,0);
56
  private static final Static3D VECTY = new Static3D(0,1,0);
57
  private static final Static3D VECTZ = new Static3D(0,0,1);
58
  private static final Static3D VECTU = new Static3D(0,0,0);
59

    
60
  private static final Static3D[] VECTORS = { VECTX, VECTY, VECTZ, VECTZ };
61

    
62
  static
63
    {
64
    int i=0;
65
    types = new Type[NUM_EFFECTS];
66

    
67
    for(Type type: Type.values())
68
      {
69
      types[i++] = type;
70
      }
71
    }
72

    
73
  private EffectListener mListener;
74
  private int mEffectReturned;
75
  private long mCurrentBaseEffectID;
76
  private int mNumDoubleScramblesLeft, mNumScramblesLeft;
77
  private int mLastVector;
78
  private long mDurationSingleTurn;
79
  private Random mRnd;
80
  private RubikObject mObject;
81

    
82
  Effect[] mNodeEffects;
83
  int[] mNodeEffectPosition;
84
  Effect[] mCubeEffects;
85
  int[] mCubeEffectPosition;
86
  int mCubeEffectNumber, mNodeEffectNumber;
87

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

    
90
  ScrambleEffect()
91
    {
92
    mRnd = new Random( System.currentTimeMillis() );
93
    mLastVector = 3;
94
    }
95

    
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97

    
98
  abstract void createEffects(int duration, int numScrambles);
99
  abstract void effectFinishedPlugin(final long effectID);
100

    
101
///////////////////////////////////////////////////////////////////////////////////////////////////
102
// first compute how many out of 'numScrambles' are double turns (this will matter when we compute
103
// the time a single quarter-turn takes!
104

    
105
  private void createBaseEffects(int duration, int numScrambles)
106
    {
107
    mNumScramblesLeft = numScrambles;
108

    
109
    mNumDoubleScramblesLeft=0;
110

    
111
    for(int i=0; i<numScrambles; i++)
112
      {
113
      if( (mRnd.nextInt() % 3) == 0 )
114
        {
115
        mNumDoubleScramblesLeft++;
116
        }
117
      }
118

    
119
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
120

    
121
    addNewScramble();
122
    }
123

    
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125

    
126
  private void addNewScramble()
127
    {
128
    if( mNumScramblesLeft>0 )
129
      {
130
      if( mLastVector == 3 )
131
        {
132
        mLastVector = mRnd.nextInt(3);
133
        }
134
      else
135
        {
136
        int newVector = mRnd.nextInt(2);
137

    
138
        switch(mLastVector)
139
          {
140
          case 0: mLastVector = (newVector==0 ? 1:2); break;
141
          case 1: mLastVector = (newVector==0 ? 0:2); break;
142
          case 2: mLastVector = (newVector==0 ? 0:1); break;
143
          }
144
        }
145

    
146
      int row  = mRnd.nextInt(mObject.getSize());
147
      int angle= randomizeAngle();
148
      int absAngle = (angle<0 ? -angle : angle);
149
      long durationMillis =  absAngle*mDurationSingleTurn;
150

    
151
      mNumScramblesLeft--;
152
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
153

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

    
159
      mCurrentBaseEffectID = mObject.addNewRotation(VECTORS[mLastVector], row, angle*90, durationMillis, this );
160
      }
161
    else
162
      {
163
      mLastVector = -1;
164

    
165
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
166
        {
167
        mListener.effectFinished(FAKE_EFFECT_ID);
168
        }
169
      }
170
    }
171

    
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173

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

    
180
    return sign==0 ? result : -result;
181
    }
182

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184

    
185
  private void assignEffects()
186
    {
187
    for(int i=0; i<mCubeEffectNumber; i++)
188
      {
189
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
190
      mCubeEffects[i].notifyWhenFinished(this);
191
      }
192

    
193
    DistortedEffects nodeEffects = mObject.getEffects();
194

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

    
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203

    
204
  private void disassignEffects()
205
    {
206
    for(int i=0; i<mCubeEffectNumber; i++)
207
      {
208
      mObject.remove(mCubeEffects[i].getID());
209
      }
210

    
211
    DistortedEffects nodeEffects = mObject.getEffects();
212

    
213
    for(int i=0; i<mNodeEffectNumber; i++)
214
      {
215
      nodeEffects.abortById(mNodeEffects[i].getID());
216
      }
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220
// PUBLIC API
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222

    
223
  @SuppressWarnings("unused")
224
  public static String[] getNames()
225
    {
226
    String[] names = new String[NUM_EFFECTS];
227

    
228
    for( int i=0; i<NUM_EFFECTS; i++)
229
      {
230
      names[i] = types[i].name();
231
      }
232

    
233
    return names;
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237

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

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245

    
246
  public void effectFinished(final long effectID)
247
    {
248
    if( effectID == mCurrentBaseEffectID )
249
      {
250
      mObject.removeRotationNow();
251
      addNewScramble();
252
      return;
253
      }
254

    
255
    for(int i=0; i<mCubeEffectNumber; i++)
256
      {
257
      long id = mCubeEffects[i].getID();
258

    
259
      if( effectID == id )
260
        {
261
        mEffectReturned++;
262
        effectFinishedPlugin(effectID);
263

    
264
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
265
          {
266
          disassignEffects();
267

    
268
          if( mNumScramblesLeft==0 )
269
            {
270
            mListener.effectFinished(FAKE_EFFECT_ID);
271
            }
272
          }
273

    
274
        return;
275
        }
276
      }
277

    
278
    for(int i=0; i<mNodeEffectNumber; i++)
279
      {
280
      long id = mNodeEffects[i].getID();
281

    
282
      if( effectID == id )
283
        {
284
        mEffectReturned++;
285
        effectFinishedPlugin(effectID);
286

    
287
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
288
          {
289
          disassignEffects();
290

    
291
          if( mNumScramblesLeft==0 )
292
            {
293
            mListener.effectFinished(FAKE_EFFECT_ID);
294
            }
295
          }
296

    
297
        return;
298
        }
299
      }
300
    }
301

    
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303

    
304
  @SuppressWarnings("unused")
305
  public long start(int duration, RubikRenderer renderer)
306
    {
307
    mObject   = renderer.getObject();
308
    mListener = renderer;
309

    
310
    mObject.solve();
311

    
312
    int numScrambles = renderer.getNumScrambles();
313
    int dura = (int)(duration*Math.pow(numScrambles,0.6f));
314
    createBaseEffects(dura,numScrambles);
315
    createEffects    (dura,numScrambles);
316

    
317
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
318
      {
319
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
320
      }
321

    
322
    assignEffects();
323

    
324
    return FAKE_EFFECT_ID;
325
    }
326

    
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328

    
329
  @SuppressWarnings("unused")
330
  public static void enableEffects()
331
    {
332
    Method method;
333

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

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