Project

General

Profile

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

magiccube / src / main / java / org / distorted / effects / scramble / ScrambleEffect.java @ 51a07bb4

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.effects.scramble;
21

    
22
import org.distorted.effects.BaseEffect;
23
import org.distorted.library.effect.Effect;
24
import org.distorted.library.main.DistortedEffects;
25
import org.distorted.library.main.DistortedScreen;
26
import org.distorted.library.message.EffectListener;
27
import org.distorted.main.RubikPreRender;
28
import org.distorted.effects.EffectController;
29
import org.distorted.objects.TwistyObject;
30

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

    
34
///////////////////////////////////////////////////////////////////////////////////////////////////
35

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

    
44
    final Class<? extends ScrambleEffect> effect;
45

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

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

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

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

    
67
  private static final int START_AXIS = -2;
68
  private static final int STOP_AXIS  = -1;
69

    
70
  private EffectController mController;
71
  private int mEffectReturned;
72
  private int mNumDoubleScramblesLeft, mNumScramblesLeft;
73
  private int mLastRotAxis, mLastRow;
74
  private long mDurationSingleTurn;
75
  private final Random mRnd;
76
  private int mBasicAngle;
77

    
78
  TwistyObject mObject;
79
  Effect[] mNodeEffects;
80
  int[] mNodeEffectPosition;
81
  Effect[] mCubeEffects;
82
  int[] mCubeEffectPosition;
83
  int mCubeEffectNumber, mNodeEffectNumber;
84
  int mNumScrambles;
85
  int[] mScramble;
86

    
87
///////////////////////////////////////////////////////////////////////////////////////////////////
88

    
89
  ScrambleEffect()
90
    {
91
    mRnd = new Random( System.currentTimeMillis() );
92
    mScramble = new int[3];
93
    mLastRotAxis = START_AXIS;
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
// Only works for
106
// basicAngle==5, i.e. something whose rotations are by  72 degrees (Megaminx) or
107
// basicAngle==4, i.e. something whose rotations are by  90 degrees (RubikCube) or
108
// basicAngle==3, i.e. something whose rotations are by 120 degrees (Pyramix) or
109
// basicAngle==2, i.e. something whose rotations are by 180 degrees (e.g. a 3x2x1 'Bunny')
110

    
111
  private void createBaseEffects(int duration, int numScrambles)
112
    {
113
    mNumScramblesLeft = numScrambles;
114

    
115
    mNumDoubleScramblesLeft=0;
116

    
117
    if( mBasicAngle>=4 )
118
      {
119
      int chance = mBasicAngle==4 ? 3:2;
120

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

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

    
133
    addNewScramble();
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
// only works if basicAngle<=5
138

    
139
  private void addNewScramble()
140
    {
141
    if( mNumScramblesLeft>0 )
142
      {
143
      mNumScrambles++;
144

    
145
      mObject.randomizeNewScramble(mScramble, mRnd,mLastRotAxis, mLastRow, mNumScrambles,
146
                                  mNumScramblesLeft, mNumDoubleScramblesLeft);
147
      mLastRotAxis = mScramble[0];
148
      mLastRow     = mScramble[1];
149
      int angle    = mScramble[2];
150

    
151
      int rowBitmap  = (1<<mLastRow);
152
      int absAngle = (angle<0 ? -angle : angle);
153
      long durationMillis = absAngle*mDurationSingleTurn;
154

    
155
      mNumScramblesLeft--;
156
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
157

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

    
163
      mController.addRotation(this, mLastRotAxis, rowBitmap, angle*(360/mBasicAngle), durationMillis);
164
      }
165
    else
166
      {
167
      mLastRotAxis = STOP_AXIS;
168

    
169
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
170
        {
171
        mController.effectFinished(FAKE_EFFECT_ID);
172
        }
173
      }
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

    
178
  private void assignEffects()
179
    {
180
    for(int i=0; i<mCubeEffectNumber; i++)
181
      {
182
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
183
      mCubeEffects[i].notifyWhenFinished(this);
184
      }
185

    
186
    DistortedEffects nodeEffects = mObject.getEffects();
187

    
188
    for(int i=0; i<mNodeEffectNumber; i++)
189
      {
190
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
191
      mNodeEffects[i].notifyWhenFinished(this);
192
      }
193
    }
194

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196

    
197
  private void disassignEffects()
198
    {
199
    for(int i=0; i<mCubeEffectNumber; i++)
200
      {
201
      mObject.remove(mCubeEffects[i].getID());
202
      }
203

    
204
    DistortedEffects nodeEffects = mObject.getEffects();
205

    
206
    for(int i=0; i<mNodeEffectNumber; i++)
207
      {
208
      nodeEffects.abortById(mNodeEffects[i].getID());
209
      }
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213
// PUBLIC API
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
  @SuppressWarnings("unused")
217
  public static String[] getNames()
218
    {
219
    String[] names = new String[NUM_EFFECTS];
220

    
221
    for( int i=0; i<NUM_EFFECTS; i++)
222
      {
223
      names[i] = types[i].name();
224
      }
225

    
226
    return names;
227
    }
228

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230

    
231
  @SuppressWarnings("unused")
232
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
233
    {
234
    return types[ordinal].effect.newInstance();
235
    }
236

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

    
239
  public void onActionFinished(final long effectID)
240
    {
241
    addNewScramble();
242
    }
243

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

    
246
  public void effectFinished(final long effectID)
247
    {
248
    for(int i=0; i<mCubeEffectNumber; i++)
249
      {
250
      long id = mCubeEffects[i].getID();
251

    
252
      if( effectID == id )
253
        {
254
        mEffectReturned++;
255
        effectFinishedPlugin(effectID);
256

    
257
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
258
          {
259
          disassignEffects();
260

    
261
          if( mNumScramblesLeft==0 )
262
            {
263
            mController.effectFinished(FAKE_EFFECT_ID);
264
            }
265
          }
266

    
267
        return;
268
        }
269
      }
270

    
271
    for(int i=0; i<mNodeEffectNumber; i++)
272
      {
273
      long id = mNodeEffects[i].getID();
274

    
275
      if( effectID == id )
276
        {
277
        mEffectReturned++;
278
        effectFinishedPlugin(effectID);
279

    
280
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
281
          {
282
          disassignEffects();
283

    
284
          if( mNumScramblesLeft==0 )
285
            {
286
            mController.effectFinished(FAKE_EFFECT_ID);
287
            }
288
          }
289

    
290
        return;
291
        }
292
      }
293
    }
294

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

    
297
  @SuppressWarnings("unused")
298
  public long start(int duration, DistortedScreen screen, EffectController cont)
299
    {
300
    mObject    = cont.getObject();
301
    mController= cont;
302

    
303
    mObject.solve();
304

    
305
    mBasicAngle = mObject.getBasicAngle();
306

    
307
    int numScrambles = cont.getNumScrambles();
308
    int dura = (int)(duration*Math.pow(numScrambles,0.6f));
309
    createBaseEffects(dura,numScrambles);
310
    createEffects    (dura,numScrambles);
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)