Project

General

Profile

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

magiccube / src / main / java / org / distorted / effects / scramble / ScrambleEffect.java @ 20dea800

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.ObjectList;
30
import org.distorted.objects.TwistyObject;
31

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

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36

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

    
45
    final Class<? extends ScrambleEffect> effect;
46

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

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

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

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

    
68
  private EffectController mController;
69
  private int mEffectReturned;
70
  private int mNumDoubleScramblesLeft, mNumScramblesLeft;
71
  private long mDurationSingleTurn;
72
  private final Random mRnd;
73
  private int mBasicAngle;
74
  private boolean mRotReady, mPluginReady;
75

    
76
  TwistyObject mObject;
77
  Effect[] mNodeEffects;
78
  int[] mNodeEffectPosition;
79
  Effect[] mCubeEffects;
80
  int[] mCubeEffectPosition;
81
  int mCubeEffectNumber, mNodeEffectNumber;
82
  int mNumScrambles;
83
  int[][] mScrambles;
84

    
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86

    
87
  ScrambleEffect()
88
    {
89
    mRnd = new Random( System.currentTimeMillis() );
90
    mScrambles = new int[ObjectList.MAX_LEVEL][3];
91
    }
92

    
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94

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

    
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99
// first compute how many out of 'numScrambles' are double turns (this will matter when we compute
100
// the time a single quarter-turn takes!
101
//
102
// Only works for
103
// basicAngle==5, i.e. something whose rotations are by  72 degrees (Megaminx) or
104
// basicAngle==4, i.e. something whose rotations are by  90 degrees (RubikCube) or
105
// basicAngle==3, i.e. something whose rotations are by 120 degrees (Pyramix) or
106
// basicAngle==2, i.e. something whose rotations are by 180 degrees (e.g. a 3x2x1 'Bunny')
107

    
108
  private void createBaseEffects(int duration, int numScrambles)
109
    {
110
    mNumScramblesLeft = numScrambles;
111
    mNumDoubleScramblesLeft=0;
112

    
113
    for(int scramble=0; scramble<mNumScramblesLeft; scramble++)
114
      {
115
      mObject.randomizeNewScramble(mScrambles, mRnd, scramble);
116
      int angle = mScrambles[scramble][2];
117
      if( angle==2 || angle==-2 ) mNumDoubleScramblesLeft++;
118
      }
119

    
120
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
121
    mNumScrambles = 0;
122

    
123
    mRotReady    = false;
124
    mPluginReady = false;
125

    
126
    addNewScramble();
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130
// only works if basicAngle<=5
131

    
132
  private void addNewScramble()
133
    {
134
    if( mNumScramblesLeft>0 )
135
      {
136
      int axis = mScrambles[mNumScrambles][0];
137
      int row  = mScrambles[mNumScrambles][1];
138
      int angle= mScrambles[mNumScrambles][2];
139

    
140
      int rowBitmap  = (1<<row);
141
      int absAngle = (angle<0 ? -angle : angle);
142
      long durationMillis = absAngle*mDurationSingleTurn;
143

    
144
      mNumScramblesLeft--;
145
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
146

    
147
      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
148
        {
149
        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
150
        }
151

    
152
      mController.addRotation(this, axis, rowBitmap, angle*(360/mBasicAngle), durationMillis);
153

    
154
      mNumScrambles++;
155
      }
156
    else
157
      {
158
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
159
        {
160
        mRotReady = true;
161
        if( mPluginReady ) mController.effectFinished(FAKE_EFFECT_ID);
162
        }
163
      }
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

    
168
  private void assignEffects()
169
    {
170
    for(int i=0; i<mCubeEffectNumber; i++)
171
      {
172
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
173
      mCubeEffects[i].notifyWhenFinished(this);
174
      }
175

    
176
    DistortedEffects nodeEffects = mObject.getEffects();
177

    
178
    for(int i=0; i<mNodeEffectNumber; i++)
179
      {
180
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
181
      mNodeEffects[i].notifyWhenFinished(this);
182
      }
183
    }
184

    
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186

    
187
  private void disassignEffects()
188
    {
189
    for(int i=0; i<mCubeEffectNumber; i++)
190
      {
191
      mObject.remove(mCubeEffects[i].getID());
192
      }
193

    
194
    DistortedEffects nodeEffects = mObject.getEffects();
195

    
196
    for(int i=0; i<mNodeEffectNumber; i++)
197
      {
198
      nodeEffects.abortById(mNodeEffects[i].getID());
199
      }
200
    }
201

    
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203
// PUBLIC API
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

    
206
  @SuppressWarnings("unused")
207
  public static String[] getNames()
208
    {
209
    String[] names = new String[NUM_EFFECTS];
210

    
211
    for( int i=0; i<NUM_EFFECTS; i++)
212
      {
213
      names[i] = types[i].name();
214
      }
215

    
216
    return names;
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  @SuppressWarnings("unused")
222
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
223
    {
224
    return types[ordinal].effect.newInstance();
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228

    
229
  public void onActionFinished(final long effectID)
230
    {
231
    addNewScramble();
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

    
236
  private void effectFinishedAction(final long effectID, final long id)
237
    {
238
    mEffectReturned++;
239
    effectFinishedPlugin(effectID);
240

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

    
245
      if( mNumScramblesLeft==0 )
246
        {
247
        mPluginReady = true;
248
        if( mRotReady ) mController.effectFinished(FAKE_EFFECT_ID);
249
        }
250
      }
251
    }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

    
255
  public void effectFinished(final long effectID)
256
    {
257
    for(int i=0; i<mCubeEffectNumber; i++)
258
      {
259
      long id = mCubeEffects[i].getID();
260

    
261
      if( effectID == id )
262
        {
263
        effectFinishedAction(effectID,id);
264
        return;
265
        }
266
      }
267

    
268
    for(int i=0; i<mNodeEffectNumber; i++)
269
      {
270
      long id = mNodeEffects[i].getID();
271

    
272
      if( effectID == id )
273
        {
274
        effectFinishedAction(effectID,id);
275
        return;
276
        }
277
      }
278
    }
279

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

    
282
  @SuppressWarnings("unused")
283
  public long start(int duration, DistortedScreen screen, EffectController cont)
284
    {
285
    mObject    = cont.getObject();
286
    mController= cont;
287

    
288
    mObject.solve();
289

    
290
    mBasicAngle = mObject.getBasicAngle();
291

    
292
    int numScrambles = cont.getNumScrambles();
293
    int dura = (int)(duration*Math.pow(numScrambles,0.6f));
294
    createBaseEffects(dura,numScrambles);
295
    createEffects    (dura,numScrambles);
296

    
297
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
298
      {
299
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
300
      }
301

    
302
    assignEffects();
303

    
304
    return FAKE_EFFECT_ID;
305
    }
306

    
307
///////////////////////////////////////////////////////////////////////////////////////////////////
308

    
309
  @SuppressWarnings("unused")
310
  public static void enableEffects()
311
    {
312
    Method method;
313

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

    
326
      try
327
        {
328
        if( method!=null ) method.invoke(null);
329
        }
330
      catch(Exception ex)
331
        {
332
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
333
        }
334
      }
335
    }
336
}
(1-1/3)