Project

General

Profile

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

magiccube / src / main / java / org / distorted / effects / scramble / ScrambleEffect.java @ 1f9772f3

1 3b12e641 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4 fdec60a3 Leszek Koltunski
// This file is part of Magic Cube.                                                              //
5 3b12e641 Leszek Koltunski
//                                                                                               //
6 fdec60a3 Leszek Koltunski
// Magic Cube is free software: you can redistribute it and/or modify                            //
7 3b12e641 Leszek Koltunski
// 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 fdec60a3 Leszek Koltunski
// Magic Cube is distributed in the hope that it will be useful,                                 //
12 3b12e641 Leszek Koltunski
// 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 fdec60a3 Leszek Koltunski
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18 3b12e641 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20 1f9772f3 Leszek Koltunski
package org.distorted.effects.scramble;
21 3b12e641 Leszek Koltunski
22 1f9772f3 Leszek Koltunski
import org.distorted.effects.BaseEffect;
23 3b12e641 Leszek Koltunski
import org.distorted.library.effect.Effect;
24
import org.distorted.library.main.DistortedEffects;
25 8becce57 Leszek Koltunski
import org.distorted.library.main.DistortedScreen;
26 3b12e641 Leszek Koltunski
import org.distorted.library.message.EffectListener;
27 1f9772f3 Leszek Koltunski
import org.distorted.main.RubikPostRender;
28
import org.distorted.objects.RubikObject;
29 3b12e641 Leszek Koltunski
30
import java.lang.reflect.Method;
31 e8764a49 Leszek Koltunski
import java.util.Random;
32 3b12e641 Leszek Koltunski
33
///////////////////////////////////////////////////////////////////////////////////////////////////
34
35 8becce57 Leszek Koltunski
public abstract class ScrambleEffect extends BaseEffect implements EffectListener, RubikPostRender.ActionFinishedListener
36 3b12e641 Leszek Koltunski
{
37
  public enum Type
38
    {
39
    NONE         (ScrambleEffectNone.class        ),
40 a62aa9d7 Leszek Koltunski
    ROTATIONS    (ScrambleEffectRotations.class   ),
41 3b12e641 Leszek Koltunski
    ;
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
  static
56
    {
57
    int i=0;
58
    types = new Type[NUM_EFFECTS];
59
60
    for(Type type: Type.values())
61
      {
62
      types[i++] = type;
63
      }
64
    }
65
66 8becce57 Leszek Koltunski
  private RubikPostRender mPostRender;
67 e8764a49 Leszek Koltunski
  private int mEffectReturned;
68
  private int mNumDoubleScramblesLeft, mNumScramblesLeft;
69
  private int mLastVector;
70
  private long mDurationSingleTurn;
71
  private Random mRnd;
72 27a70eae Leszek Koltunski
  private RubikObject mObject;
73 e844c116 Leszek Koltunski
  private int mNumAxis;
74
  private int mBasicAngle;
75 d12bb11b Leszek Koltunski
  private int mSize;
76 3b12e641 Leszek Koltunski
77 e8764a49 Leszek Koltunski
  Effect[] mNodeEffects;
78
  int[] mNodeEffectPosition;
79
  Effect[] mCubeEffects;
80
  int[] mCubeEffectPosition;
81
  int mCubeEffectNumber, mNodeEffectNumber;
82 3b12e641 Leszek Koltunski
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84
85
  ScrambleEffect()
86
    {
87 e8764a49 Leszek Koltunski
    mRnd = new Random( System.currentTimeMillis() );
88 e844c116 Leszek Koltunski
    mLastVector = -2;
89 3b12e641 Leszek Koltunski
    }
90
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92
93 e4db5995 Leszek Koltunski
  abstract void createEffects(int duration, int numScrambles);
94 a62aa9d7 Leszek Koltunski
  abstract void effectFinishedPlugin(final long effectID);
95 3b12e641 Leszek Koltunski
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97 47ba5ddc Leszek Koltunski
// first compute how many out of 'numScrambles' are double turns (this will matter when we compute
98
// the time a single quarter-turn takes!
99 e844c116 Leszek Koltunski
//
100
// Only works for
101 769d7b9f Leszek Koltunski
// basicAngle==4, i.e. something whose rotations are by  90 degrees (RubikCube) or
102 e844c116 Leszek Koltunski
// basicAngle==3, i.e. something whose rotations are by 120 degrees (a Pyramix) or
103 769d7b9f Leszek Koltunski
// basicAngle==2, i.e. something whose rotations are by 180 degrees (e.g. a 3x2x1 'Bunny')
104 e8764a49 Leszek Koltunski
105 a62aa9d7 Leszek Koltunski
  private void createBaseEffects(int duration, int numScrambles)
106 3b12e641 Leszek Koltunski
    {
107 e8764a49 Leszek Koltunski
    mNumScramblesLeft = numScrambles;
108
109
    mNumDoubleScramblesLeft=0;
110
111 e844c116 Leszek Koltunski
    if( mBasicAngle>=4 )
112 e8764a49 Leszek Koltunski
      {
113 e844c116 Leszek Koltunski
      for(int i=0; i<numScrambles; i++)
114 e8764a49 Leszek Koltunski
        {
115 e844c116 Leszek Koltunski
        if( (mRnd.nextInt() % 3) == 0 )
116
          {
117
          mNumDoubleScramblesLeft++;
118
          }
119 e8764a49 Leszek Koltunski
        }
120
      }
121
122
    mDurationSingleTurn = duration/(mNumScramblesLeft+mNumDoubleScramblesLeft);
123
124
    addNewScramble();
125 a62aa9d7 Leszek Koltunski
    }
126 3b12e641 Leszek Koltunski
127 a62aa9d7 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
128 769d7b9f Leszek Koltunski
// only works if basicAngle<=4, i.e. won't work for something whose basic rotations are by less
129 e844c116 Leszek Koltunski
// than 90 degrees.
130 3b12e641 Leszek Koltunski
131 e8764a49 Leszek Koltunski
  private void addNewScramble()
132 a62aa9d7 Leszek Koltunski
    {
133 e8764a49 Leszek Koltunski
    if( mNumScramblesLeft>0 )
134
      {
135 e844c116 Leszek Koltunski
      if( mLastVector == -2 )
136 e8764a49 Leszek Koltunski
        {
137 e844c116 Leszek Koltunski
        mLastVector = mRnd.nextInt(mNumAxis);
138 e8764a49 Leszek Koltunski
        }
139
      else
140
        {
141 e844c116 Leszek Koltunski
        int newVector = mRnd.nextInt(mNumAxis-1);
142
        mLastVector = (newVector>=mLastVector ? newVector+1 : newVector);
143 e8764a49 Leszek Koltunski
        }
144
145 d12bb11b Leszek Koltunski
      int rowBitmap  = (1<<mRnd.nextInt(mSize));
146 e8764a49 Leszek Koltunski
      int angle= randomizeAngle();
147
      int absAngle = (angle<0 ? -angle : angle);
148
      long durationMillis =  absAngle*mDurationSingleTurn;
149
150
      mNumScramblesLeft--;
151
      if( absAngle==2 ) mNumDoubleScramblesLeft--;
152 3b12e641 Leszek Koltunski
153 2ecf0c21 Leszek Koltunski
      if( mNumScramblesLeft==0 && mNumDoubleScramblesLeft!=0 )
154
        {
155
        android.util.Log.e("effect", "ERROR: "+mNumDoubleScramblesLeft);
156
        }
157
158 8becce57 Leszek Koltunski
      mPostRender.addRotation(this, mLastVector, rowBitmap, angle*(360/mBasicAngle), durationMillis);
159 e8764a49 Leszek Koltunski
      }
160
    else
161
      {
162
      mLastVector = -1;
163 035fe333 Leszek Koltunski
164
      if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
165
        {
166 8becce57 Leszek Koltunski
        mPostRender.effectFinished(FAKE_EFFECT_ID);
167 035fe333 Leszek Koltunski
        }
168 e8764a49 Leszek Koltunski
      }
169
    }
170
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172 769d7b9f Leszek Koltunski
// only works for basicAngle<=4.
173 e8764a49 Leszek Koltunski
174
  private int randomizeAngle()
175
    {
176 2ecf0c21 Leszek Koltunski
    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 3b12e641 Leszek Koltunski
    }
182
183 47ba5ddc Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
184
185
  private void assignEffects()
186
    {
187
    for(int i=0; i<mCubeEffectNumber; i++)
188
      {
189 27a70eae Leszek Koltunski
      mObject.apply(mCubeEffects[i],mCubeEffectPosition[i]);
190 47ba5ddc Leszek Koltunski
      mCubeEffects[i].notifyWhenFinished(this);
191
      }
192
193 27a70eae Leszek Koltunski
    DistortedEffects nodeEffects = mObject.getEffects();
194 47ba5ddc Leszek Koltunski
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 27a70eae Leszek Koltunski
      mObject.remove(mCubeEffects[i].getID());
209 47ba5ddc Leszek Koltunski
      }
210
211 27a70eae Leszek Koltunski
    DistortedEffects nodeEffects = mObject.getEffects();
212 47ba5ddc Leszek Koltunski
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 3b12e641 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
245
246 8becce57 Leszek Koltunski
  public void onActionFinished(final long effectID)
247 3b12e641 Leszek Koltunski
    {
248 8becce57 Leszek Koltunski
    addNewScramble();
249
    }
250 e8764a49 Leszek Koltunski
251 8becce57 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
252
253
  public void effectFinished(final long effectID)
254
    {
255 e8764a49 Leszek Koltunski
    for(int i=0; i<mCubeEffectNumber; i++)
256 3b12e641 Leszek Koltunski
      {
257 e8764a49 Leszek Koltunski
      long id = mCubeEffects[i].getID();
258
259
      if( effectID == id )
260 a62aa9d7 Leszek Koltunski
        {
261 e8764a49 Leszek Koltunski
        mEffectReturned++;
262
        effectFinishedPlugin(effectID);
263 a62aa9d7 Leszek Koltunski
264 e8764a49 Leszek Koltunski
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
265 a62aa9d7 Leszek Koltunski
          {
266 e8764a49 Leszek Koltunski
          disassignEffects();
267 035fe333 Leszek Koltunski
268
          if( mNumScramblesLeft==0 )
269
            {
270 8becce57 Leszek Koltunski
            mPostRender.effectFinished(FAKE_EFFECT_ID);
271 035fe333 Leszek Koltunski
            }
272 e8764a49 Leszek Koltunski
          }
273 a62aa9d7 Leszek Koltunski
274 e8764a49 Leszek Koltunski
        return;
275
        }
276
      }
277 a62aa9d7 Leszek Koltunski
278 e8764a49 Leszek Koltunski
    for(int i=0; i<mNodeEffectNumber; i++)
279
      {
280
      long id = mNodeEffects[i].getID();
281 a62aa9d7 Leszek Koltunski
282 e8764a49 Leszek Koltunski
      if( effectID == id )
283 a62aa9d7 Leszek Koltunski
        {
284 e8764a49 Leszek Koltunski
        mEffectReturned++;
285
        effectFinishedPlugin(effectID);
286 a62aa9d7 Leszek Koltunski
287 e8764a49 Leszek Koltunski
        if( mEffectReturned == mCubeEffectNumber+mNodeEffectNumber )
288 a62aa9d7 Leszek Koltunski
          {
289 e8764a49 Leszek Koltunski
          disassignEffects();
290 035fe333 Leszek Koltunski
291
          if( mNumScramblesLeft==0 )
292
            {
293 8becce57 Leszek Koltunski
            mPostRender.effectFinished(FAKE_EFFECT_ID);
294 035fe333 Leszek Koltunski
            }
295 a62aa9d7 Leszek Koltunski
          }
296 e8764a49 Leszek Koltunski
297
        return;
298 a62aa9d7 Leszek Koltunski
        }
299 3b12e641 Leszek Koltunski
      }
300
    }
301
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303
304 47ba5ddc Leszek Koltunski
  @SuppressWarnings("unused")
305 8becce57 Leszek Koltunski
  public long start(int duration, DistortedScreen screen, RubikPostRender post)
306 3b12e641 Leszek Koltunski
    {
307 8becce57 Leszek Koltunski
    mObject     = post.getObject();
308
    mPostRender = post;
309 a62aa9d7 Leszek Koltunski
310 27a70eae Leszek Koltunski
    mObject.solve();
311 beb325a0 Leszek Koltunski
312 12ad3fca Leszek Koltunski
    mNumAxis    = mObject.getRotationAxis().length;
313 e844c116 Leszek Koltunski
    mBasicAngle = mObject.getBasicAngle();
314 d12bb11b Leszek Koltunski
    mSize       = mObject.getSize();
315 e844c116 Leszek Koltunski
316 8becce57 Leszek Koltunski
    int numScrambles = post.getNumScrambles();
317 e4db5995 Leszek Koltunski
    int dura = (int)(duration*Math.pow(numScrambles,0.6f));
318
    createBaseEffects(dura,numScrambles);
319
    createEffects    (dura,numScrambles);
320 a62aa9d7 Leszek Koltunski
321 e8764a49 Leszek Koltunski
    if( mCubeEffectNumber==0 && mNodeEffectNumber==0 )
322 a62aa9d7 Leszek Koltunski
      {
323
      throw new RuntimeException("Cube and Node Plugin Effects not created!");
324
      }
325
326 e8764a49 Leszek Koltunski
    assignEffects();
327 3b12e641 Leszek Koltunski
328
    return FAKE_EFFECT_ID;
329
    }
330
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332
333
  @SuppressWarnings("unused")
334
  public static void enableEffects()
335
    {
336
    Method method;
337
338
    for(Type type: Type.values())
339
      {
340
      try
341
        {
342
        method = type.effect.getDeclaredMethod("enable"); // enable not public, thus getDeclaredMethod
343
        }
344
      catch(NoSuchMethodException ex)
345
        {
346
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception getting method: "+ex.getMessage());
347
        method = null;
348
        }
349
350
      try
351
        {
352
        if( method!=null ) method.invoke(null);
353
        }
354
      catch(Exception ex)
355
        {
356
        android.util.Log.e("ScrambleEffect", type.effect.getSimpleName()+": exception invoking method: "+ex.getMessage());
357
        }
358
      }
359
    }
360
}