Project

General

Profile

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

magiccube / src / main / java / org / distorted / external / RubikScores.java @ 6142069a

1 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 1c327853 Leszek Koltunski
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10 acabdd83 Leszek Koltunski
package org.distorted.external;
11 f0e87514 Leszek Koltunski
12 a7d8c3cd Leszek Koltunski
import java.util.HashMap;
13 3f7a4363 Leszek Koltunski
import java.util.UUID;
14
15 82ce8e64 Leszek Koltunski
import android.content.Context;
16 f0e87514 Leszek Koltunski
import android.content.SharedPreferences;
17 82ce8e64 Leszek Koltunski
import android.telephony.TelephonyManager;
18 1c90c64a Leszek Koltunski
19 25445dcf Leszek Koltunski
import com.google.firebase.crashlytics.FirebaseCrashlytics;
20
21 3f7a4363 Leszek Koltunski
import org.distorted.main.BuildConfig;
22 a7d8c3cd Leszek Koltunski
import org.distorted.objects.RubikObject;
23
import org.distorted.objects.RubikObjectList;
24 6142069a Leszek Koltunski
import org.distorted.screens.RubikScreenPlay;
25 f0e87514 Leszek Koltunski
26 5bda8973 Leszek Koltunski
import static org.distorted.objectlib.main.ObjectType.MAX_SCRAMBLES;
27 d433b50e Leszek Koltunski
28 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
29 82ce8e64 Leszek Koltunski
// hold my own scores, and some other statistics.
30 f0e87514 Leszek Koltunski
31
public class RubikScores
32
  {
33 5bda8973 Leszek Koltunski
  public static final int MAX_RECORD = 10;
34 a7d8c3cd Leszek Koltunski
  public static final int MULT = 1000000;
35 1c90c64a Leszek Koltunski
  public static final long NO_RECORD = Long.MAX_VALUE;
36 714292f1 Leszek Koltunski
  private static RubikScores mThis;
37
38 82ce8e64 Leszek Koltunski
  private String mName, mCountry;
39 c3ffcf58 Leszek Koltunski
  private boolean mNameIsVerified;
40
  private int mNumRuns;
41
  private int mNumPlays;
42 59aee296 Leszek Koltunski
  private int mNumWins;
43 82ce8e64 Leszek Koltunski
  private int mDeviceID;
44 f0e87514 Leszek Koltunski
45 a7d8c3cd Leszek Koltunski
  private static class MapValue
46
    {
47
    long record;
48
    boolean submitted;
49
50
    MapValue(long rec,int sub)
51
      {
52
      record    = rec;
53
      submitted = sub!=0;
54
      }
55
    }
56
57
  private final HashMap<Integer,MapValue> mMap;
58
59 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
60
61 714292f1 Leszek Koltunski
  private RubikScores()
62 f0e87514 Leszek Koltunski
    {
63 a7d8c3cd Leszek Koltunski
    mMap = new HashMap<>();
64 c3ffcf58 Leszek Koltunski
65 f895e77a Leszek Koltunski
    mName = "";
66 82ce8e64 Leszek Koltunski
    mCountry = "un";
67
68 c3ffcf58 Leszek Koltunski
    mNameIsVerified = false;
69 82ce8e64 Leszek Koltunski
70 59aee296 Leszek Koltunski
    mNumPlays= -1;
71
    mNumRuns = -1;
72
    mDeviceID= -1;
73
    mNumWins =  0;
74 f0e87514 Leszek Koltunski
    }
75
76 a7d8c3cd Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
77
78
  private int mapKey(int object,int level)
79
    {
80
    return object*MULT + level;
81
    }
82
83 17f9a695 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
84
85
  private int privateGetDeviceID()
86
    {
87
    int id;
88
89
    try
90
      {
91
      String s = UUID.randomUUID().toString();
92 874c37b1 Leszek Koltunski
      id = s.hashCode();
93 17f9a695 Leszek Koltunski
      }
94
    catch(Exception ex)
95
      {
96
      id = 0;
97
      android.util.Log.e("scores", "Exception in getDeviceID()");
98
      }
99
100
    return id<0 ? -id : id;
101
    }
102
103
///////////////////////////////////////////////////////////////////////////////////////////////////
104 e06e1b7e Leszek Koltunski
105
  synchronized void successfulSubmit()
106
    {
107
    mNameIsVerified = true;
108
109 a7d8c3cd Leszek Koltunski
    for(int key: mMap.keySet())
110
      {
111
      MapValue value = mMap.get(key);
112
      if( value!=null ) value.submitted = true;
113
      }
114 e06e1b7e Leszek Koltunski
    }
115
116 714292f1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
117
118 e06e1b7e Leszek Koltunski
  int getDeviceID()
119 714292f1 Leszek Koltunski
    {
120 e06e1b7e Leszek Koltunski
    return mDeviceID;
121
    }
122 714292f1 Leszek Koltunski
123 f0e87514 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
124
125 e06e1b7e Leszek Koltunski
  synchronized boolean thereAreUnsubmittedRecords()
126 f0e87514 Leszek Koltunski
    {
127 a7d8c3cd Leszek Koltunski
    for(int key: mMap.keySet())
128
      {
129
      MapValue value = mMap.get(key);
130
      if( value!=null && !value.submitted && value.record<NO_RECORD) return true;
131
      }
132 c3ffcf58 Leszek Koltunski
133 e06e1b7e Leszek Koltunski
    return false;
134 f0e87514 Leszek Koltunski
    }
135
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
138 e06e1b7e Leszek Koltunski
  synchronized String getRecordList(String strObj, String strLvl, String strTim)
139 f0e87514 Leszek Koltunski
    {
140 e06e1b7e Leszek Koltunski
    StringBuilder builderObj = new StringBuilder();
141
    StringBuilder builderLvl = new StringBuilder();
142
    StringBuilder builderTim = new StringBuilder();
143
    boolean first = true;
144 f0e87514 Leszek Koltunski
145 a7d8c3cd Leszek Koltunski
    for(int key: mMap.keySet())
146 f0e87514 Leszek Koltunski
      {
147 a7d8c3cd Leszek Koltunski
      MapValue value = mMap.get(key);
148 f0e87514 Leszek Koltunski
149 a7d8c3cd Leszek Koltunski
      if( value!=null && !value.submitted && value.record<NO_RECORD)
150 f0e87514 Leszek Koltunski
        {
151 a7d8c3cd Leszek Koltunski
        if( !first )
152 f0e87514 Leszek Koltunski
          {
153 a7d8c3cd Leszek Koltunski
          builderObj.append(',');
154
          builderLvl.append(',');
155
          builderTim.append(',');
156
          }
157
        first=false;
158 7ac0ee88 Leszek Koltunski
159 a7d8c3cd Leszek Koltunski
        RubikObject object = RubikObjectList.getObject(key/MULT);
160
161
        if( object!=null )
162
          {
163 84d746d7 Leszek Koltunski
          builderObj.append(object.getUpperName());
164 a7d8c3cd Leszek Koltunski
          builderLvl.append(key%MULT);
165
          builderTim.append(value.record);
166 f0e87514 Leszek Koltunski
          }
167
        }
168
      }
169 c3ffcf58 Leszek Koltunski
170 e06e1b7e Leszek Koltunski
    return strObj+builderObj.toString()+strLvl+builderLvl.toString()+strTim+builderTim.toString();
171
    }
172 82ce8e64 Leszek Koltunski
173 e06e1b7e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
174
// Public API
175 ee4e7896 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
176
177
  public boolean isVerified()
178
    {
179
    return mNameIsVerified;
180
    }
181
182 c3ffcf58 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
183
184 e06e1b7e Leszek Koltunski
  public int getNumPlays()
185 c3ffcf58 Leszek Koltunski
    {
186 e06e1b7e Leszek Koltunski
    return mNumPlays;
187 c3ffcf58 Leszek Koltunski
    }
188
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190
191 e06e1b7e Leszek Koltunski
  public int getNumRuns()
192 c3ffcf58 Leszek Koltunski
    {
193 e06e1b7e Leszek Koltunski
    return mNumRuns;
194 c3ffcf58 Leszek Koltunski
    }
195
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197
198 e06e1b7e Leszek Koltunski
  public String getName()
199 c3ffcf58 Leszek Koltunski
    {
200 e06e1b7e Leszek Koltunski
    return mName;
201
    }
202 1c90c64a Leszek Koltunski
203 e06e1b7e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
204
205
  public String getCountry()
206
    {
207
    return mCountry;
208 1c90c64a Leszek Koltunski
    }
209
210 286d73ae Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
211
212 e06e1b7e Leszek Koltunski
  public void incrementNumPlays()
213 286d73ae Leszek Koltunski
    {
214 e06e1b7e Leszek Koltunski
    mNumPlays++;
215
    }
216 286d73ae Leszek Koltunski
217 e06e1b7e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
218 82ce8e64 Leszek Koltunski
219 e06e1b7e Leszek Koltunski
  public void incrementNumRuns()
220
    {
221
    mNumRuns++;
222
    }
223 82ce8e64 Leszek Koltunski
224 e06e1b7e Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
225 82ce8e64 Leszek Koltunski
226 59aee296 Leszek Koltunski
  public int incrementNumWins()
227 e06e1b7e Leszek Koltunski
    {
228 59aee296 Leszek Koltunski
    mNumWins++;
229
    return mNumWins;
230 e06e1b7e Leszek Koltunski
    }
231
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233
234
  public void setName(String newName)
235
    {
236
    mName = newName;
237 82ce8e64 Leszek Koltunski
    }
238
239 d7e539d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
240
241 a7d8c3cd Leszek Koltunski
  public synchronized boolean setRecord(int object, int level, long record)
242
    {
243 83018ac4 Leszek Koltunski
    int key = mapKey(object,level);
244 a7d8c3cd Leszek Koltunski
    MapValue oldValue = mMap.get(key);
245
246
    if( oldValue==null )
247
      {
248
      MapValue value = new MapValue(record,0);
249
      mMap.put(key,value);
250
      return true;
251
      }
252
253
    long oldRecord = oldValue.record;
254
255
    if( oldRecord>record)
256
      {
257
      MapValue value = new MapValue(record,0);
258
      mMap.put(key,value);
259
      return true;
260
      }
261
262
    return false;
263
    }
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265
266
  public synchronized long getRecord(int object, int level)
267
    {
268
    int key = mapKey(object,level);
269
    MapValue value = mMap.get(key);
270
    return value!=null ? value.record : NO_RECORD;
271
    }
272
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274
275
  public synchronized boolean isSolved(int object, int level)
276 d7e539d0 Leszek Koltunski
    {
277 a7d8c3cd Leszek Koltunski
    int key = mapKey(object,level);
278
    MapValue value = mMap.get(key);
279
    return value!=null && value.record<NO_RECORD;
280 d7e539d0 Leszek Koltunski
    }
281
282 714292f1 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
283
284 e06e1b7e Leszek Koltunski
  public void setCountry(Context context)
285 714292f1 Leszek Koltunski
    {
286 e06e1b7e Leszek Koltunski
    TelephonyManager tM =((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
287 714292f1 Leszek Koltunski
288 e06e1b7e Leszek Koltunski
    if( tM!=null )
289 714292f1 Leszek Koltunski
      {
290 e06e1b7e Leszek Koltunski
      mCountry = tM.getSimCountryIso();
291
292
      if( mCountry==null || mCountry.length()<=1 )
293
        {
294
        mCountry = tM.getNetworkCountryIso();
295
        }
296 714292f1 Leszek Koltunski
      }
297
298 e06e1b7e Leszek Koltunski
    // Special case: Dominicana. Its ISO-3166-alpha-2 country code is 'do' which we can't have here
299
    // because we later on map this to a resource name (the flag) and 'do' is a reserved Java keyword
300
    // and can't be a resource name.
301
302
    if( mCountry.equals("do") ) mCountry = "dm";
303 714292f1 Leszek Koltunski
    }
304 c3ffcf58 Leszek Koltunski
305 c8249cf6 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
306
307
  public void setCountry(String country)
308
    {
309
    mCountry = country;
310
311
    if( mCountry.equals("do") ) mCountry = "dm";  // see above
312
    }
313
314 286d73ae Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
315
316 e06e1b7e Leszek Koltunski
  public static RubikScores getInstance()
317 286d73ae Leszek Koltunski
    {
318 9333086d Leszek Koltunski
    if( mThis==null ) mThis = new RubikScores();
319 e06e1b7e Leszek Koltunski
    return mThis;
320 286d73ae Leszek Koltunski
    }
321
322 17f9a695 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
323
324 e06e1b7e Leszek Koltunski
  public synchronized void savePreferences(SharedPreferences.Editor editor)
325 17f9a695 Leszek Koltunski
    {
326 a7d8c3cd Leszek Koltunski
    int numObjects = RubikObjectList.getNumObjects();
327 e06e1b7e Leszek Koltunski
    StringBuilder builder = new StringBuilder();
328 1c90c64a Leszek Koltunski
329 5bda8973 Leszek Koltunski
    for(int level=0; level<=MAX_RECORD; level++)
330 e06e1b7e Leszek Koltunski
      {
331
      builder.setLength(0);
332 1c90c64a Leszek Koltunski
333 a7d8c3cd Leszek Koltunski
      for(int object=0; object<numObjects; object++)
334 e06e1b7e Leszek Koltunski
        {
335 a7d8c3cd Leszek Koltunski
        int key = mapKey(object,level);
336
        RubikObject obj = RubikObjectList.getObject(object);
337
        MapValue value = mMap.get(key);
338
339
        if( obj!=null && value!=null && value.record<NO_RECORD )
340
          {
341 84d746d7 Leszek Koltunski
          builder.append(obj.getUpperName());
342 a7d8c3cd Leszek Koltunski
          builder.append("=");
343
          builder.append(value.record);
344
          builder.append(",");
345
          builder.append(value.submitted ? 1:0 );
346
          builder.append(" ");
347
          }
348 e06e1b7e Leszek Koltunski
        }
349 c3ffcf58 Leszek Koltunski
350 e06e1b7e Leszek Koltunski
      editor.putString("scores_record"+level, builder.toString());
351
      }
352 c3ffcf58 Leszek Koltunski
353 e06e1b7e Leszek Koltunski
    editor.putString("scores_name"  , mName  );
354
    editor.putBoolean("scores_isVerified", mNameIsVerified);
355
    editor.putInt("scores_numPlays", mNumPlays);
356 59aee296 Leszek Koltunski
    editor.putInt("scores_numRuns" , mNumRuns );
357 e06e1b7e Leszek Koltunski
    editor.putInt("scores_deviceid", mDeviceID);
358 59aee296 Leszek Koltunski
    editor.putInt("scores_review"  , mNumWins );
359 c3ffcf58 Leszek Koltunski
    }
360
361
///////////////////////////////////////////////////////////////////////////////////////////////////
362
363 e06e1b7e Leszek Koltunski
  public synchronized void restorePreferences(SharedPreferences preferences)
364 c3ffcf58 Leszek Koltunski
    {
365 9333086d Leszek Koltunski
    String recordStr, subStr, nameStr, timeStr, submStr, errorStr="";
366 5bda8973 Leszek Koltunski
    int start, end, equals, comma, ordinal, subm;
367 e06e1b7e Leszek Koltunski
    long time;
368 25445dcf Leszek Koltunski
    boolean thereWasError = false;
369 a7d8c3cd Leszek Koltunski
    int numObjects = RubikObjectList.getNumObjects();
370 c3ffcf58 Leszek Koltunski
371 5bda8973 Leszek Koltunski
    for(int level=0; level<=MAX_SCRAMBLES; level++)
372 e06e1b7e Leszek Koltunski
      {
373 5bda8973 Leszek Koltunski
      recordStr = preferences.getString("scores_record"+level, null);
374
      if( recordStr==null ) continue;
375 e06e1b7e Leszek Koltunski
      start = end = 0;
376 c3ffcf58 Leszek Koltunski
377 e06e1b7e Leszek Koltunski
      while( end!=-1 )
378
        {
379
        end = recordStr.indexOf(" ", start);
380 4895fff6 Leszek Koltunski
381 e06e1b7e Leszek Koltunski
        if( end==-1 ) subStr = recordStr.substring(start);
382
        else          subStr = recordStr.substring(start,end);
383 4895fff6 Leszek Koltunski
384 e06e1b7e Leszek Koltunski
        start = end+1;
385 4895fff6 Leszek Koltunski
386 e06e1b7e Leszek Koltunski
        equals = subStr.indexOf("=");
387 9333086d Leszek Koltunski
        comma  = subStr.indexOf(",");
388 4895fff6 Leszek Koltunski
389 9333086d Leszek Koltunski
        if( equals>=0 && comma>=0 )
390 4c0cd600 Leszek Koltunski
          {
391 9333086d Leszek Koltunski
          nameStr = subStr.substring(0,equals);
392 e06e1b7e Leszek Koltunski
          timeStr = subStr.substring(equals+1,comma);
393
          submStr = subStr.substring(comma+1);
394
395 5bda8973 Leszek Koltunski
          ordinal = RubikObjectList.getOrdinal(nameStr);
396 e06e1b7e Leszek Koltunski
397 5bda8973 Leszek Koltunski
          if( ordinal>=0 && ordinal<numObjects )
398 4895fff6 Leszek Koltunski
            {
399 e06e1b7e Leszek Koltunski
            time = Long.parseLong(timeStr);
400
            subm = Integer.parseInt(submStr);
401
402 7ac0ee88 Leszek Koltunski
            if( subm>=0 && subm<=1 )
403 e06e1b7e Leszek Koltunski
              {
404 a7d8c3cd Leszek Koltunski
              MapValue value = new MapValue(time,subm);
405 5bda8973 Leszek Koltunski
              int key = mapKey(ordinal,level);
406 a7d8c3cd Leszek Koltunski
              mMap.put(key,value);
407 e06e1b7e Leszek Koltunski
              }
408
            else
409
              {
410 9333086d Leszek Koltunski
              errorStr += ("error1: subm="+subm+" obj: "+nameStr+"\n");
411 25445dcf Leszek Koltunski
              thereWasError= true;
412 e06e1b7e Leszek Koltunski
              }
413
            }
414
          else
415
            {
416 5bda8973 Leszek Koltunski
            errorStr += ("error2: object="+ordinal+" obj: "+nameStr+"\n");
417 25445dcf Leszek Koltunski
            thereWasError = true;
418 4895fff6 Leszek Koltunski
            }
419 4c0cd600 Leszek Koltunski
          }
420 e06e1b7e Leszek Koltunski
        }
421 4895fff6 Leszek Koltunski
      }
422
423 e06e1b7e Leszek Koltunski
    mName           = preferences.getString("scores_name"  , "" );
424
    mNameIsVerified = preferences.getBoolean("scores_isVerified", false);
425
    mNumPlays       = preferences.getInt("scores_numPlays", 0);
426
    mNumRuns        = preferences.getInt("scores_numRuns" , 0);
427
    mDeviceID       = preferences.getInt("scores_deviceid",-1);
428 59aee296 Leszek Koltunski
    mNumWins        = preferences.getInt("scores_review"  , 0);
429 e06e1b7e Leszek Koltunski
430
    if( mDeviceID==-1 ) mDeviceID = privateGetDeviceID();
431 25445dcf Leszek Koltunski
432
    if( thereWasError ) recordDBError(errorStr);
433
    }
434
435 6142069a Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
436
437
  public int numberOfSolvedMAXes()
438
    {
439
    int numObjects = RubikObjectList.getNumObjects();
440
    int ret=0, level = RubikScreenPlay.LEVELS_SHOWN;
441
442
    for(int obj=0; obj<numObjects; obj++)
443
      {
444
      if( isSolved(obj,level) ) ret++;
445
      }
446
447
    return ret;
448
    }
449
450 25445dcf Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
451
452
  public void recordDBError(String message)
453
    {
454
    if( BuildConfig.DEBUG )
455
      {
456
      android.util.Log.e("scores", message);
457
      }
458
    else
459
      {
460
      Exception ex = new Exception(message);
461
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
462
      crashlytics.setCustomKey("scores" , message);
463
      crashlytics.recordException(ex);
464
      }
465 4895fff6 Leszek Koltunski
    }
466 f0e87514 Leszek Koltunski
  }