Project

General

Profile

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

magiccube / src / main / java / org / distorted / network / RubikScores.java @ 3f7a4363

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 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.network;
21

    
22
import java.util.UUID;
23

    
24
import android.content.Context;
25
import android.content.SharedPreferences;
26
import android.telephony.TelephonyManager;
27

    
28
import com.google.firebase.crashlytics.FirebaseCrashlytics;
29

    
30
import static org.distorted.objectlib.main.ObjectList.MAX_NUM_OBJECTS;
31
import static org.distorted.objectlib.main.ObjectList.NUM_OBJECTS;
32
import static org.distorted.objectlib.main.ObjectList.MAX_LEVEL;
33

    
34
import org.distorted.objectlib.main.ObjectList;
35

    
36
import org.distorted.main.BuildConfig;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39
// hold my own scores, and some other statistics.
40

    
41
public class RubikScores
42
  {
43
  public static final long NO_RECORD = Long.MAX_VALUE;
44
  private static RubikScores mThis;
45

    
46
  private final long[][][] mRecords;
47
  private final int [][][] mSubmitted;
48

    
49
  private String mName, mCountry;
50
  private boolean mNameIsVerified;
51
  private int mNumRuns;
52
  private int mNumPlays;
53
  private int mNumWins;
54
  private int mDeviceID;
55

    
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57

    
58
  private RubikScores()
59
    {
60
    mRecords   = new long[NUM_OBJECTS][MAX_NUM_OBJECTS][MAX_LEVEL];
61
    mSubmitted = new int [NUM_OBJECTS][MAX_NUM_OBJECTS][MAX_LEVEL];
62

    
63
    for(int i=0; i<NUM_OBJECTS; i++)
64
      for(int j=0; j<MAX_NUM_OBJECTS; j++)
65
        for(int k=0; k<MAX_LEVEL; k++)
66
          {
67
          mRecords[i][j][k]   = NO_RECORD;
68
          mSubmitted[i][j][k] = 0;
69
          }
70

    
71
    mName = "";
72
    mCountry = "un";
73

    
74
    mNameIsVerified = false;
75

    
76
    mNumPlays= -1;
77
    mNumRuns = -1;
78
    mDeviceID= -1;
79
    mNumWins =  0;
80
    }
81

    
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83

    
84
  private int privateGetDeviceID()
85
    {
86
    int id;
87

    
88
    try
89
      {
90
      String s = UUID.randomUUID().toString();
91
      id = s.hashCode();
92
      }
93
    catch(Exception ex)
94
      {
95
      id = 0;
96
      android.util.Log.e("scores", "Exception in getDeviceID()");
97
      }
98

    
99
    return id<0 ? -id : id;
100
    }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
  synchronized void successfulSubmit()
105
    {
106
    mNameIsVerified = true;
107

    
108
    for(int i=0; i<NUM_OBJECTS; i++)
109
      for(int j=0; j<MAX_NUM_OBJECTS; j++)
110
        for(int k=0; k<MAX_LEVEL; k++)
111
          {
112
          mSubmitted[i][j][k]=1;
113
          }
114
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117

    
118
  int getDeviceID()
119
    {
120
    return mDeviceID;
121
    }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124

    
125
  synchronized boolean thereAreUnsubmittedRecords()
126
    {
127
    ObjectList list;
128
    int length;
129

    
130
    for(int object=0; object<NUM_OBJECTS; object++)
131
      {
132
      list = ObjectList.getObject(object);
133
      length = list.getSizes().length;
134

    
135
      for(int size=0; size<length; size++)
136
        for(int level=0; level<MAX_LEVEL; level++)
137
          {
138
          if( mSubmitted[object][size][level]==0 && mRecords[object][size][level]<NO_RECORD )
139
            {
140
            return true;
141
            }
142
          }
143
      }
144

    
145
    return false;
146
    }
147

    
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

    
150
  synchronized String getRecordList(String strObj, String strLvl, String strTim)
151
    {
152
    ObjectList list;
153
    StringBuilder builderObj = new StringBuilder();
154
    StringBuilder builderLvl = new StringBuilder();
155
    StringBuilder builderTim = new StringBuilder();
156
    boolean first = true;
157
    int[] sizes;
158
    int length;
159

    
160
    for(int object=0; object<NUM_OBJECTS; object++)
161
      {
162
      list = ObjectList.getObject(object);
163
      sizes = list.getSizes();
164
      length = sizes.length;
165

    
166
      for(int size=0; size<length; size++)
167
        {
168
        for(int level=0; level<MAX_LEVEL; level++)
169
          {
170
          if( mSubmitted[object][size][level]==0 && mRecords[object][size][level]<NO_RECORD )
171
            {
172
            if( !first )
173
              {
174
              builderObj.append(',');
175
              builderLvl.append(',');
176
              builderTim.append(',');
177
              }
178
            else
179
              {
180
              first=false;
181
              }
182

    
183
            builderObj.append(list.name());
184
            builderObj.append("_");
185
            builderObj.append(sizes[size]);
186
            builderLvl.append(level);
187
            builderTim.append(mRecords[object][size][level]);
188
            }
189
          }
190
        }
191
      }
192

    
193
    return strObj+builderObj.toString()+strLvl+builderLvl.toString()+strTim+builderTim.toString();
194
    }
195

    
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197
// Public API
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
  public synchronized long getRecord(int object, int size, int level)
201
    {
202
    int maxsize = ObjectList.getObject(object).getSizes().length;
203

    
204
    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && level>=0 && level<MAX_LEVEL )
205
      {
206
      return mRecords[object][size][level];
207
      }
208

    
209
    return -1;
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  public synchronized boolean isSubmitted(int object, int size, int level)
215
    {
216
    int maxsize = ObjectList.getObject(object).getSizes().length;
217

    
218
    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && level>=0 && level<MAX_LEVEL )
219
      {
220
      return mSubmitted[object][size][level]==1;
221
      }
222

    
223
    return false;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  public boolean isVerified()
229
    {
230
    return mNameIsVerified;
231
    }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

    
235
  public int getNumPlays()
236
    {
237
    return mNumPlays;
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

    
242
  public int getNumRuns()
243
    {
244
    return mNumRuns;
245
    }
246

    
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248

    
249
  public String getName()
250
    {
251
    return mName;
252
    }
253

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

    
256
  public String getCountry()
257
    {
258
    return mCountry;
259
    }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
  public void incrementNumPlays()
264
    {
265
    mNumPlays++;
266
    }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

    
270
  public void incrementNumRuns()
271
    {
272
    mNumRuns++;
273
    }
274

    
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276

    
277
  public int incrementNumWins()
278
    {
279
    mNumWins++;
280
    return mNumWins;
281
    }
282

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

    
285
  public void setName(String newName)
286
    {
287
    mName = newName;
288
    }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
  public synchronized boolean isSolved(int object, int size, int level)
293
    {
294
    int maxsize = ObjectList.getObject(object).getSizes().length;
295

    
296
    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && level>=0 && level<MAX_LEVEL )
297
      {
298
      return mRecords[object][size][level]<NO_RECORD;
299
      }
300

    
301
    return false;
302
    }
303

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305

    
306
  public void setCountry(Context context)
307
    {
308
    TelephonyManager tM =((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
309

    
310
    if( tM!=null )
311
      {
312
      mCountry = tM.getSimCountryIso();
313

    
314
      if( mCountry==null || mCountry.length()<=1 )
315
        {
316
        mCountry = tM.getNetworkCountryIso();
317
        }
318
      }
319

    
320
    // Special case: Dominicana. Its ISO-3166-alpha-2 country code is 'do' which we can't have here
321
    // because we later on map this to a resource name (the flag) and 'do' is a reserved Java keyword
322
    // and can't be a resource name.
323

    
324
    if( mCountry.equals("do") ) mCountry = "dm";
325
    }
326

    
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328

    
329
  public void setCountry(String country)
330
    {
331
    mCountry = country;
332

    
333
    if( mCountry.equals("do") ) mCountry = "dm";  // see above
334
    }
335

    
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337

    
338
  public static RubikScores getInstance()
339
    {
340
    if( mThis==null )
341
      {
342
      mThis = new RubikScores();
343
      }
344

    
345
    return mThis;
346
    }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  public synchronized void savePreferences(SharedPreferences.Editor editor)
351
    {
352
    StringBuilder builder = new StringBuilder();
353
    ObjectList list;
354
    int[] sizes;
355
    int length;
356

    
357
    for(int level=0; level<MAX_LEVEL; level++)
358
      {
359
      builder.setLength(0);
360

    
361
      for(int object=0; object<NUM_OBJECTS; object++)
362
        {
363
        list = ObjectList.getObject(object);
364
        sizes = list.getSizes();
365
        length = sizes.length;
366

    
367
        for(int size=0; size<length; size++)
368
          {
369
          builder.append(list.name());
370
          builder.append("_");
371
          builder.append(sizes[size]);
372
          builder.append("=");
373
          builder.append(mRecords[object][size][level]);
374
          builder.append(",");
375
          builder.append(mSubmitted[object][size][level]);
376
          builder.append(" ");
377
          }
378
        }
379

    
380
      editor.putString("scores_record"+level, builder.toString());
381
      }
382

    
383
    editor.putString("scores_name"  , mName  );
384
    editor.putBoolean("scores_isVerified", mNameIsVerified);
385
    editor.putInt("scores_numPlays", mNumPlays);
386
    editor.putInt("scores_numRuns" , mNumRuns );
387
    editor.putInt("scores_deviceid", mDeviceID);
388
    editor.putInt("scores_review"  , mNumWins );
389
    }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

    
393
  public synchronized void restorePreferences(SharedPreferences preferences)
394
    {
395
    String recordStr, subStr, nameStr, sizeStr, timeStr, submStr, errorStr="";
396
    int start, end, equals, underscore, comma;
397
    int object, sizeIndex, subm;
398
    long time;
399
    boolean thereWasError = false;
400

    
401
    for(int level=0; level<MAX_LEVEL; level++)
402
      {
403
      start = end = 0;
404
      recordStr = preferences.getString("scores_record"+level, "");
405

    
406
      while( end!=-1 )
407
        {
408
        end = recordStr.indexOf(" ", start);
409

    
410
        if( end==-1 ) subStr = recordStr.substring(start);
411
        else          subStr = recordStr.substring(start,end);
412

    
413
        start = end+1;
414

    
415
        underscore = subStr.indexOf("_");
416
        equals = subStr.indexOf("=");
417
        comma = subStr.indexOf(",");
418

    
419
        if( underscore>=0 && equals>=0 && comma>=0 )
420
          {
421
          nameStr = subStr.substring(0,underscore);
422
          sizeStr = subStr.substring(underscore+1, equals);
423
          timeStr = subStr.substring(equals+1,comma);
424
          submStr = subStr.substring(comma+1);
425

    
426
          object = ObjectList.getOrdinal(nameStr);
427

    
428
          if( object>=0 && object< NUM_OBJECTS )
429
            {
430
            sizeIndex = ObjectList.getSizeIndex(object,Integer.parseInt(sizeStr));
431
            time = Long.parseLong(timeStr);
432
            subm = Integer.parseInt(submStr);
433

    
434
            if( sizeIndex>=0 && sizeIndex<MAX_NUM_OBJECTS && subm>=0 && subm<=1 )
435
              {
436
              mRecords  [object][sizeIndex][level] = time;
437
              mSubmitted[object][sizeIndex][level] = subm;
438
              }
439
            else
440
              {
441
              errorStr += ("error1: size="+sizeIndex+" subm="+subm+" obj: "+nameStr+" size: "+sizeStr+"\n");
442
              thereWasError= true;
443
              }
444
            }
445
          else
446
            {
447
            errorStr += ("error2: object="+object+" obj: "+nameStr+" size: "+sizeStr+"\n");
448
            thereWasError = true;
449
            }
450
          }
451
        }
452
      }
453

    
454
    mName           = preferences.getString("scores_name"  , "" );
455
    mNameIsVerified = preferences.getBoolean("scores_isVerified", false);
456
    mNumPlays       = preferences.getInt("scores_numPlays", 0);
457
    mNumRuns        = preferences.getInt("scores_numRuns" , 0);
458
    mDeviceID       = preferences.getInt("scores_deviceid",-1);
459
    mNumWins        = preferences.getInt("scores_review"  , 0);
460

    
461
    if( mDeviceID==-1 ) mDeviceID = privateGetDeviceID();
462

    
463
    if( thereWasError ) recordDBError(errorStr);
464
    }
465

    
466
///////////////////////////////////////////////////////////////////////////////////////////////////
467

    
468
  public void recordDBError(String message)
469
    {
470
    if( BuildConfig.DEBUG )
471
      {
472
      android.util.Log.e("scores", message);
473
      }
474
    else
475
      {
476
      Exception ex = new Exception(message);
477
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
478
      crashlytics.setCustomKey("scores" , message);
479
      crashlytics.recordException(ex);
480
      }
481
    }
482

    
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484

    
485
  public synchronized boolean setRecord(int object, int size, int level, long timeTaken)
486
    {
487
    int maxsize = ObjectList.getObject(object).getSizes().length;
488

    
489
    if( object>=0 && object<NUM_OBJECTS && size>=0 && size<maxsize && level>=1 && level<=MAX_LEVEL )
490
      {
491
      if( mRecords[object][size][level-1]> timeTaken )
492
        {
493
        mRecords  [object][size][level-1] = timeTaken;
494
        mSubmitted[object][size][level-1] = 0;
495
        return true;
496
        }
497
      }
498

    
499
    return false;
500
    }
501
  }
(2-2/2)