Project

General

Profile

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

magiccube / src / main / java / org / distorted / network / RubikScores.java @ 6a083c6a

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 android.content.Context;
23
import android.content.SharedPreferences;
24
import android.telephony.TelephonyManager;
25

    
26
import com.google.firebase.crashlytics.FirebaseCrashlytics;
27

    
28
import org.distorted.main.BuildConfig;
29
import org.distorted.objects.ObjectList;
30

    
31
import java.util.UUID;
32

    
33
import static org.distorted.objects.ObjectList.MAX_NUM_OBJECTS;
34
import static org.distorted.objects.ObjectList.NUM_OBJECTS;
35
import static org.distorted.objects.ObjectList.MAX_LEVEL;
36

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

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

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

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

    
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56

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

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

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

    
73
    mNameIsVerified = false;
74

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

    
81
///////////////////////////////////////////////////////////////////////////////////////////////////
82

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

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

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

    
101
///////////////////////////////////////////////////////////////////////////////////////////////////
102

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

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

    
115
///////////////////////////////////////////////////////////////////////////////////////////////////
116

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

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

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

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

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

    
144
    return false;
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

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

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

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

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

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

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196
// Public API
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198

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

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

    
208
    return -1;
209
    }
210

    
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212

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

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

    
222
    return false;
223
    }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226

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

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233

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

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

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

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

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

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

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

    
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261

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

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

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

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

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

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283

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

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

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

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

    
300
    return false;
301
    }
302

    
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304

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

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

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

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

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

    
326
///////////////////////////////////////////////////////////////////////////////////////////////////
327

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

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

    
335
///////////////////////////////////////////////////////////////////////////////////////////////////
336

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

    
344
    return mThis;
345
    }
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

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

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

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

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

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

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

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391

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

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

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

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

    
412
        start = end+1;
413

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

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

    
425
          object = ObjectList.getOrdinal(nameStr);
426

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

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

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

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

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

    
465
///////////////////////////////////////////////////////////////////////////////////////////////////
466

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

    
482
///////////////////////////////////////////////////////////////////////////////////////////////////
483

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

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

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