Project

General

Profile

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

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

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.magic.RubikRenderer;
27
import org.distorted.object.RubikObject;
28

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

    
32
import static org.distorted.object.RubikObjectList.VECTX;
33
import static org.distorted.object.RubikObjectList.VECTY;
34
import static org.distorted.object.RubikObjectList.VECTZ;
35

    
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

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

    
46
    final Class<? extends ScrambleEffect> effect;
47

    
48
    Type(Class<? extends ScrambleEffect> effect)
49
      {
50
      this.effect= effect;
51
      }
52
    }
53

    
54
  private static int NUM_EFFECTS = Type.values().length;
55
  private static final int FAKE_EFFECT_ID  = -3;
56
  private static final Type[] types;
57

    
58
  static
59
    {
60
    int i=0;
61
    types = new Type[NUM_EFFECTS];
62

    
63
    for(Type type: Type.values())
64
      {
65
      types[i++] = type;
66
      }
67
    }
68

    
69
  private EffectListener mListener;
70
  private int mEffectReturned;
71
  private long mCurrentBaseEffectID;
72
  private int mNumDoubleScramblesLeft, mNumScramblesLeft;
73
  private int mLastVector;
74
  private long mDurationSingleTurn;
75
  private Random mRnd;
76
  private RubikObject mObject;
77

    
78
  Effect[] mNodeEffects;
79
  int[] mNodeEffectPosition;
80
  Effect[] mCubeEffects;
81
  int[] mCubeEffectPosition;
82
  int mCubeEffectNumber, mNodeEffectNumber;
83

    
84
///////////////////////////////////////////////////////////////////////////////////////////////////
85

    
86
  ScrambleEffect()
87
    {
88
    mRnd = new Random( System.currentTimeMillis() );
89
    mLastVector = -1;
90
    }
91

    
92
///////////////////////////////////////////////////////////////////////////////////////////////////
93

    
94
  abstract void createEffects(int duration, int numScrambles);
95
  abstract void effectFinishedPlugin(final long effectID);
96

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98
// first compute how many out of 'numScrambles' are double turns (this will matter when we compute
99
// the time a single quarter-turn takes!
100

    
101
  private void createBaseEffects(int duration, int numScrambles)
102
    {
103
    mNumScramblesLeft = numScrambles;
104

    
105
    mNumDoubleScramblesLeft=0;
106

    
107
    for(int i=0; i<numScrambles; i++)
108
      {
109
      if( (mRnd.nextInt() % 3) == 0 )
110
        {
111
        mNumDoubleScramblesLeft++;
112
        }
113
      }
114

    
115
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
116

    
117
    addNewScramble();
118
    }
119

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121

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

    
139
        switch(mLastVector)
140
          {
141
          case VECTX: mLastVector = (newVector==0 ? VECTY: VECTZ); break;
142
          case VECTY: mLastVector = (newVector==0 ? VECTX: VECTZ); break;
143
          case VECTZ: mLastVector = (newVector==0 ? VECTX: VECTY); break;
144
          }
145
        }
146

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

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

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

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

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

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

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

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

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

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

    
194
    DistortedEffects nodeEffects = mObject.getEffects();
195

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

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

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

    
212
    DistortedEffects nodeEffects = mObject.getEffects();
213

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

    
220
///////////////////////////////////////////////////////////////////////////////////////////////////
221
// PUBLIC API
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

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

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

    
234
    return names;
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

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

    
245
///////////////////////////////////////////////////////////////////////////////////////////////////
246

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

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

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

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

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

    
275
        return;
276
        }
277
      }
278

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

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

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

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

    
298
        return;
299
        }
300
      }
301
    }
302

    
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304

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

    
311
    mObject.solve();
312

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

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

    
323
    assignEffects();
324

    
325
    return FAKE_EFFECT_ID;
326
    }
327

    
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329

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

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

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