Project

General

Profile

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

magiccube / src / main / java / org / distorted / effects / scramble / ScrambleEffect.java @ 5043d5d0

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

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

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

    
86
  ScrambleEffect()
87
    {
88
    mRnd = new Random( System.currentTimeMillis() );
89
    mScrambles = new int[ObjectList.MAX_LEVEL][3];
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
// Only works for
102
// basicAngle==5, i.e. something whose rotations are by  72 degrees (Megaminx) or
103
// basicAngle==4, i.e. something whose rotations are by  90 degrees (RubikCube) or
104
// basicAngle==3, i.e. something whose rotations are by 120 degrees (Pyramix) or
105
// basicAngle==2, i.e. something whose rotations are by 180 degrees (e.g. a 3x2x1 'Bunny')
106

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

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

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

    
122
    addNewScramble();
123
    }
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126
// only works if basicAngle<=5
127

    
128
  private void addNewScramble()
129
    {
130
    if( mNumScramblesLeft>0 )
131
      {
132
      int axis = mScrambles[mNumScrambles][0];
133
      int row  = mScrambles[mNumScrambles][1];
134
      int angle= mScrambles[mNumScrambles][2];
135

    
136
      int rowBitmap  = (1<<row);
137
      int absAngle = (angle<0 ? -angle : angle);
138
      long durationMillis = absAngle*mDurationSingleTurn;
139

    
140
      mNumScramblesLeft--;
141
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
142

    
143
      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
144
        {
145
        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
146
        }
147

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

    
150
      mNumScrambles++;
151
      }
152
    else
153
      {
154
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
155
        {
156
        mController.effectFinished(FAKE_EFFECT_ID);
157
        }
158
      }
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  private void assignEffects()
164
    {
165
    for(int i=0; i<mCubeEffectNumber; i++)
166
      {
167
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
168
      mCubeEffects[i].notifyWhenFinished(this);
169
      }
170

    
171
    DistortedEffects nodeEffects = mObject.getEffects();
172

    
173
    for(int i=0; i<mNodeEffectNumber; i++)
174
      {
175
      nodeEffects.apply(mNodeEffects[i],mNodeEffectPosition[i]);
176
      mNodeEffects[i].notifyWhenFinished(this);
177
      }
178
    }
179

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

    
182
  private void disassignEffects()
183
    {
184
    for(int i=0; i<mCubeEffectNumber; i++)
185
      {
186
      mObject.remove(mCubeEffects[i].getID());
187
      }
188

    
189
    DistortedEffects nodeEffects = mObject.getEffects();
190

    
191
    for(int i=0; i<mNodeEffectNumber; i++)
192
      {
193
      nodeEffects.abortById(mNodeEffects[i].getID());
194
      }
195
    }
196

    
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198
// PUBLIC API
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

    
201
  @SuppressWarnings("unused")
202
  public static String[] getNames()
203
    {
204
    String[] names = new String[NUM_EFFECTS];
205

    
206
    for( int i=0; i<NUM_EFFECTS; i++)
207
      {
208
      names[i] = types[i].name();
209
      }
210

    
211
    return names;
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
  @SuppressWarnings("unused")
217
  public static ScrambleEffect create(int ordinal) throws InstantiationException, IllegalAccessException
218
    {
219
    return types[ordinal].effect.newInstance();
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223

    
224
  public void onActionFinished(final long effectID)
225
    {
226
    addNewScramble();
227
    }
228

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

    
231
  public void effectFinished(final long effectID)
232
    {
233
    for(int i=0; i<mCubeEffectNumber; i++)
234
      {
235
      long id = mCubeEffects[i].getID();
236

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

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

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

    
252
        return;
253
        }
254
      }
255

    
256
    for(int i=0; i<mNodeEffectNumber; i++)
257
      {
258
      long id = mNodeEffects[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
            mController.effectFinished(FAKE_EFFECT_ID);
272
            }
273
          }
274

    
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)