Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyBandagedAbstract.java @ 925ed78f

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 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.objects;
21

    
22
import android.content.res.Resources;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25

    
26
import org.distorted.helpers.FactoryCubit;
27
import org.distorted.helpers.FactorySticker;
28
import org.distorted.library.effect.MatrixEffectQuaternion;
29
import org.distorted.library.effect.VertexEffect;
30
import org.distorted.library.effect.VertexEffectMove;
31
import org.distorted.library.effect.VertexEffectRotate;
32
import org.distorted.library.effect.VertexEffectScale;
33
import org.distorted.library.main.DistortedEffects;
34
import org.distorted.library.main.DistortedTexture;
35
import org.distorted.library.mesh.MeshBase;
36
import org.distorted.library.mesh.MeshJoined;
37
import org.distorted.library.mesh.MeshPolygon;
38
import org.distorted.library.mesh.MeshSquare;
39
import org.distorted.library.type.Static1D;
40
import org.distorted.library.type.Static3D;
41
import org.distorted.library.type.Static4D;
42

    
43
///////////////////////////////////////////////////////////////////////////////////////////////////
44

    
45
abstract class TwistyBandagedAbstract extends TwistyObject
46
{
47
  // the three rotation axis of a 3x3 Cube. Must be normalized.
48
  static final Static3D[] ROT_AXIS = new Static3D[]
49
         {
50
           new Static3D(1,0,0),
51
           new Static3D(0,1,0),
52
           new Static3D(0,0,1)
53
         };
54

    
55
  private static final int[] BASIC_ANGLE = new int[] { 4,4,4 };
56

    
57
  private static final int[] FACE_COLORS = new int[]
58
         {
59
           COLOR_YELLOW, COLOR_WHITE,
60
           COLOR_BLUE  , COLOR_GREEN,
61
           COLOR_RED   , COLOR_ORANGE
62
         };
63

    
64
  private static final Static4D[] QUATS = new Static4D[]
65
         {
66
         new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),
67
         new Static4D(  1.0f,   0.0f,   0.0f,   0.0f),
68
         new Static4D(  0.0f,   1.0f,   0.0f,   0.0f),
69
         new Static4D(  0.0f,   0.0f,   1.0f,   0.0f),
70

    
71
         new Static4D( SQ2/2,  SQ2/2,  0.0f ,   0.0f),
72
         new Static4D( SQ2/2, -SQ2/2,  0.0f ,   0.0f),
73
         new Static4D( SQ2/2,   0.0f,  SQ2/2,   0.0f),
74
         new Static4D(-SQ2/2,   0.0f,  SQ2/2,   0.0f),
75
         new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),
76
         new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),
77
         new Static4D(  0.0f,  SQ2/2,  SQ2/2,   0.0f),
78
         new Static4D(  0.0f,  SQ2/2, -SQ2/2,   0.0f),
79
         new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),
80
         new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),
81
         new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),
82
         new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),
83

    
84
         new Static4D(  0.5f,   0.5f,   0.5f,   0.5f),
85
         new Static4D(  0.5f,   0.5f,  -0.5f,   0.5f),
86
         new Static4D(  0.5f,   0.5f,  -0.5f,  -0.5f),
87
         new Static4D(  0.5f,  -0.5f,   0.5f,  -0.5f),
88
         new Static4D( -0.5f,  -0.5f,  -0.5f,   0.5f),
89
         new Static4D( -0.5f,   0.5f,  -0.5f,  -0.5f),
90
         new Static4D( -0.5f,   0.5f,   0.5f,  -0.5f),
91
         new Static4D( -0.5f,   0.5f,   0.5f,   0.5f)
92
         };
93

    
94
  private static final Static4D[] INIT_QUATS = new Static4D[]
95
        {
96
        new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),  // NULL
97
        new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),  // X
98
        new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),  // Y
99
        new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),  // Z
100
        new Static4D( -0.5f,  +0.5f,  -0.5f,  +0.5f),  // ZX
101
        new Static4D( +0.5f,  +0.5f,  +0.5f,  -0.5f),  // YX
102
        };
103

    
104
  private static final int[][] mDimensions = new int[][]
105
        {
106
         {1,1,1},  // has to be X>=Z>=Y so that all
107
         {2,1,1},  // the faces are horizontal
108
         {3,1,1},
109
         {2,1,2},
110
         {2,2,2}
111
        };
112

    
113
  private static final int[][] mStickerDimensions = new int[][]
114
        {
115
         {1,1},  // dimensions of the faces of
116
         {2,1},  // the cuboids defined above
117
         {3,1},
118
         {2,2}
119
        };
120

    
121
  private static final int[][] mFaceMap = new int[][] // cubitface=2 when rotated by
122
    {                                                 // quatIndex=1 gets moved to
123
        {0,0,5,2,4,2},                                // position mFaceMap[2][1]
124
        {1,1,4,3,5,3},
125
        {2,4,2,1,1,4},
126
        {3,5,3,0,0,5},
127
        {4,3,0,4,3,0},
128
        {5,2,1,5,2,1}
129
    };
130

    
131
  private static final int[][] mAxisMap = new int[][] // axis=1 when rotated by
132
    {                                                 // quatIndex=2 gets moved to
133
        {0,0,2,1,2,1},                                // axis mAxisMap[1][2]
134
        {1,2,1,0,0,2},
135
        {2,1,0,2,1,0}
136
    };
137

    
138
  private static final int NUM_STICKERS = mStickerDimensions.length;
139

    
140
  private static MeshBase[] mMeshes;
141

    
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

    
144
  TwistyBandagedAbstract(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
145
                         DistortedEffects effects, int[][] moves, ObjectList list, Resources res, int scrWidth)
146
    {
147
    super(size, size, quat, texture, mesh, effects, moves, list, res, scrWidth);
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

    
152
  abstract float[][] getPositions();
153
  abstract int[] getQuatIndices();
154

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

    
157
  int getCubitVariant(int cubit)
158
    {
159
    float[][] pos = getPositions();
160

    
161
    if( cubit>=0 && cubit< pos.length )
162
      {
163
      int numPoints = pos[cubit].length/3;
164
      return numPoints==8 ? 4 : numPoints-1;
165
      }
166

    
167
    return 1;
168
    }
169

    
170
///////////////////////////////////////////////////////////////////////////////////////////////////
171

    
172
  int getNumCubits()
173
    {
174
    return getPositions().length;
175
    }
176

    
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178

    
179
  float[] getCubitPosition(int cubit)
180
    {
181
    float[][] pos = getPositions();
182

    
183
    return ( cubit>=0 && cubit< pos.length ) ? pos[cubit] : null;
184
    }
185

    
186
///////////////////////////////////////////////////////////////////////////////////////////////////
187

    
188
  private int getQuatIndex(int cubit)
189
    {
190
    int[] indices = getQuatIndices();
191

    
192
    return ( cubit>=0 && cubit< indices.length ) ? indices[cubit] : 0;
193
    }
194

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196

    
197
  private float[] createVertices(int A, int B)
198
    {
199
    float E = 0.5f / Math.max(A,B);
200
    return new float[] { -A*E,-B*E, +A*E,-B*E, +A*E,+B*E, -A*E,+B*E };
201
    }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  private MeshBase createCuboid(int[] dimensions)
206
    {
207
    FactoryCubit factory = FactoryCubit.getInstance();
208

    
209
    int X = dimensions[0];
210
    int Y = dimensions[1];
211
    int Z = dimensions[2];
212

    
213
    float[] verticesXY = createVertices(X,Y);
214
    float[] verticesXZ = createVertices(X,Z);
215
    float[] verticesYZ = createVertices(Z,Y);
216

    
217
    float defHeight = 0.048f;
218

    
219
    float[] bandsX = factory.computeBands( defHeight/X,65,0.25f,0.5f,5);
220
    float[] bandsY = factory.computeBands( defHeight/Y,65,0.25f,0.5f,5);
221
    float[] bandsZ = factory.computeBands( defHeight/Z,65,0.25f,0.5f,5);
222

    
223
    MeshBase[] meshes = new MeshPolygon[6];
224

    
225
    meshes[0] = new MeshPolygon(verticesYZ,bandsX,1,2);
226
    meshes[0].setEffectAssociation(0,1,0);
227
    meshes[1] = meshes[0].copy(true);
228
    meshes[1].setEffectAssociation(0,2,0);
229
    meshes[2] = new MeshPolygon(verticesXZ,bandsY,1,2);
230
    meshes[2].setEffectAssociation(0,4,0);
231
    meshes[3] = meshes[2].copy(true);
232
    meshes[3].setEffectAssociation(0,8,0);
233
    meshes[4] = new MeshPolygon(verticesXY,bandsZ,1,2);
234
    meshes[4].setEffectAssociation(0,16,0);
235
    meshes[5] = meshes[4].copy(true);
236
    meshes[5].setEffectAssociation(0,32,0);
237

    
238
    return new MeshJoined(meshes);
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  private VertexEffect[] createCuboidEffects(int[] dimensions)
244
    {
245
    float X = dimensions[0];
246
    float Y = dimensions[1];
247
    float Z = dimensions[2];
248

    
249
    float MAX_XY = Math.max(X,Y);
250
    float MAX_XZ = Math.max(X,Z);
251
    float MAX_YZ = Math.max(Z,Y);
252

    
253
    Static1D angle = new Static1D(90);
254
    Static3D move  = new Static3D( 0.0f, 0.0f, 0.5f);
255
    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
256
    Static3D axisY = new Static3D( 0.0f, 1.0f, 0.0f);
257
    Static3D center= new Static3D( 0.0f, 0.0f, 0.0f);
258

    
259
    Static3D scale3 = new Static3D(MAX_XY,MAX_XY,+Z);
260
    Static3D scale4 = new Static3D(MAX_XY,MAX_XY,-Z);
261
    Static3D scale5 = new Static3D(MAX_XZ,+Y,MAX_XZ);
262
    Static3D scale6 = new Static3D(MAX_XZ,-Y,MAX_XZ);
263
    Static3D scale7 = new Static3D(+X,MAX_YZ,MAX_YZ);
264
    Static3D scale8 = new Static3D(-X,MAX_YZ,MAX_YZ);
265

    
266
    VertexEffect[] effect = new VertexEffect[9];
267

    
268
    effect[0] = new VertexEffectMove(move);
269
    effect[1] = new VertexEffectRotate(angle, axisX, center);
270
    effect[2] = new VertexEffectRotate(angle, axisY, center);
271
    effect[3] = new VertexEffectScale(scale3);
272
    effect[4] = new VertexEffectScale(scale4);
273
    effect[5] = new VertexEffectScale(scale5);
274
    effect[6] = new VertexEffectScale(scale6);
275
    effect[7] = new VertexEffectScale(scale7);
276
    effect[8] = new VertexEffectScale(scale8);
277

    
278
    effect[1].setMeshAssociation(12,-1);  // meshes 2,3
279
    effect[2].setMeshAssociation( 3,-1);  // meshes 0,1
280
    effect[3].setMeshAssociation(16,-1);  // mesh 4
281
    effect[4].setMeshAssociation(32,-1);  // mesh 5
282
    effect[5].setMeshAssociation( 8,-1);  // mesh 3
283
    effect[6].setMeshAssociation( 4,-1);  // mesh 2
284
    effect[7].setMeshAssociation( 1,-1);  // mesh 0
285
    effect[8].setMeshAssociation( 2,-1);  // mesh 1
286

    
287
    return effect;
288
    }
289

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

    
292
  private MeshBase createCuboidMesh(int[] dimensions)
293
    {
294
    MeshBase mesh = createCuboid(dimensions);
295
    VertexEffect[] effects = createCuboidEffects(dimensions);
296
    for( VertexEffect effect : effects ) mesh.apply(effect);
297

    
298
    int X = dimensions[0];
299
    int Y = dimensions[1];
300
    int Z = dimensions[2];
301

    
302
    float strength = 0.04f;
303
    float radius   = 0.15f;
304

    
305
    Static3D[] vertices = new Static3D[1];
306
    Static3D center;
307
    FactoryCubit factory = FactoryCubit.getInstance();
308

    
309
    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,+0.5f*Z);
310
    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
311
    factory.roundCorners(mesh, center, vertices, strength, radius);
312

    
313
    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,-0.5f*Z);
314
    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
315
    factory.roundCorners(mesh, center, vertices, strength, radius);
316

    
317
    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,+0.5f*Z);
318
    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
319
    factory.roundCorners(mesh, center, vertices, strength, radius);
320

    
321
    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,-0.5f*Z);
322
    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
323
    factory.roundCorners(mesh, center, vertices, strength, radius);
324

    
325
    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,+0.5f*Z);
326
    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
327
    factory.roundCorners(mesh, center, vertices, strength, radius);
328

    
329
    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,-0.5f*Z);
330
    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
331
    factory.roundCorners(mesh, center, vertices, strength, radius);
332

    
333
    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,+0.5f*Z);
334
    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
335
    factory.roundCorners(mesh, center, vertices, strength, radius);
336

    
337
    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,-0.5f*Z);
338
    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
339
    factory.roundCorners(mesh, center, vertices, strength, radius);
340

    
341
    mesh.mergeEffComponents();
342

    
343
    return mesh;
344
    }
345

    
346
///////////////////////////////////////////////////////////////////////////////////////////////////
347

    
348
  MeshBase createCubitMesh(int cubit, int numLayers)
349
    {
350
    if( mMeshes==null )
351
      {
352
      int LEN = mDimensions.length;
353
      mMeshes = new MeshBase[LEN];
354

    
355
      for(int i=0; i<LEN; i++)
356
        {
357
        mMeshes[i] = createCuboidMesh(mDimensions[i]);
358
        }
359
      }
360

    
361
    int variant = getCubitVariant(cubit);
362
    MeshBase mesh = mMeshes[variant].copy(true);
363
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( INIT_QUATS[getQuatIndex(cubit)], new Static3D(0,0,0) );
364
    mesh.apply(quat,0xffffffff,0);
365

    
366
    return mesh;
367
    }
368

    
369
///////////////////////////////////////////////////////////////////////////////////////////////////
370

    
371
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
372
    {
373
    int numFaces = FACE_COLORS.length;
374
    int stickerType = face/numFaces;
375
    int color = face%numFaces;
376
    float X = mStickerDimensions[stickerType][0];
377
    float Y = mStickerDimensions[stickerType][1];
378
    float MAX = Math.max(X,Y);
379
    float R = 0.10f / MAX;
380
    float S = 0.08f / MAX;
381
    X /= (2*MAX);
382
    Y /= (2*MAX);
383

    
384
    float[] vertices = { -X,-Y, +X,-Y, +X,+Y, -X,+Y};
385

    
386
    FactorySticker factory = FactorySticker.getInstance();
387
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[color], R);
388
    }
389

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

    
392
  float[][] getCubitPositions(int size)
393
    {
394
    int numCubits = getNumCubits();
395
    float[][] tmp = new float[numCubits][];
396

    
397
    for(int cubit=0; cubit<numCubits; cubit++)
398
      {
399
      tmp[cubit] = getCubitPosition(cubit);
400
      }
401

    
402
    return tmp;
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

    
407
  Static4D[] getQuats()
408
    {
409
    return QUATS;
410
    }
411

    
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413

    
414
  boolean shouldResetTextureMaps()
415
    {
416
    return false;
417
    }
418

    
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420

    
421
  int getNumFaces()
422
    {
423
    return FACE_COLORS.length;
424
    }
425

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427

    
428
  float[] getCuts(int numLayers)
429
    {
430
    float[] cuts = new float[numLayers-1];
431

    
432
    for(int i=0; i<numLayers-1; i++)
433
      {
434
      cuts[i] = (2-numLayers)*0.5f + i;
435
      }
436

    
437
    return cuts;
438
    }
439

    
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441

    
442
  int getNumStickerTypes(int numLayers)
443
    {
444
    return NUM_STICKERS;
445
    }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

    
449
  int getNumCubitFaces()
450
    {
451
    return FACE_COLORS.length;
452
    }
453

    
454
///////////////////////////////////////////////////////////////////////////////////////////////////
455

    
456
  float getScreenRatio()
457
    {
458
    return 0.5f;
459
    }
460

    
461
///////////////////////////////////////////////////////////////////////////////////////////////////
462

    
463
  private int retStickerIndex(int horzSize, int vertSize)
464
    {
465
    switch(horzSize)
466
      {
467
      case 1: return 0;
468
      case 2: return vertSize==1 ? 1:3;
469
      case 3: return 2;
470
      }
471

    
472
    return 0;
473
    }
474

    
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476

    
477
  private int getStickerIndex(int cubitface, int[] dim)
478
    {
479
    switch(cubitface)
480
      {
481
      case 0: case 1: return retStickerIndex(dim[2],dim[1]);
482
      case 2: case 3: return retStickerIndex(dim[0],dim[2]);
483
      case 4: case 5: return retStickerIndex(dim[0],dim[1]);
484
      }
485

    
486
    return 0;
487
    }
488

    
489
///////////////////////////////////////////////////////////////////////////////////////////////////
490

    
491
  int getFaceColor(int cubit, int cubitface, int numLayers)
492
    {
493
    int variant      = getCubitVariant(cubit);
494
    int[] dim        = mDimensions[variant];
495
    float[] pos      = getCubitPosition(cubit);
496
    int stickerIndex = getStickerIndex(cubitface,dim);
497
    int quatIndex    = getQuatIndex(cubit);
498
    int face         = mFaceMap[cubitface][quatIndex];
499
    int multiplier   = (face%2)==0 ? 1:-1;
500
    int posIndex     = face/2;
501
    int dimIndex     = mAxisMap[posIndex][quatIndex];
502

    
503
    float position = 0.0f;
504
    int len = pos.length/3;
505
    for(int i=0; i<len; i++) position += pos[3*i+posIndex];
506
    position /= len;
507

    
508
    boolean reaches  = multiplier*position + dim[dimIndex]*0.5f > (numLayers-1)*0.5f;
509

    
510
    return reaches ? stickerIndex*NUM_FACES + face : NUM_STICKERS*NUM_FACES;
511
    }
512

    
513
///////////////////////////////////////////////////////////////////////////////////////////////////
514

    
515
  int computeBitmapFromRow(int rowBitmap, int axis)
516
    {
517
    int bitmap, initBitmap=0;
518

    
519
    while( initBitmap!=rowBitmap )
520
      {
521
      initBitmap = rowBitmap;
522

    
523
      for(int cubit=0; cubit<NUM_CUBITS; cubit++)
524
        {
525
        bitmap = CUBITS[cubit].mRotationRow[axis];
526
        if( (rowBitmap & bitmap) != 0 ) rowBitmap |= bitmap;
527
        }
528
      }
529

    
530
    return rowBitmap;
531
    }
532

    
533
///////////////////////////////////////////////////////////////////////////////////////////////////
534

    
535
  float returnMultiplier()
536
    {
537
    return getNumLayers();
538
    }
539

    
540
///////////////////////////////////////////////////////////////////////////////////////////////////
541
// PUBLIC API
542

    
543
  public Static3D[] getRotationAxis()
544
    {
545
    return ROT_AXIS;
546
    }
547

    
548
///////////////////////////////////////////////////////////////////////////////////////////////////
549

    
550
  public int[] getBasicAngle()
551
    {
552
    return BASIC_ANGLE;
553
    }
554

    
555
///////////////////////////////////////////////////////////////////////////////////////////////////
556

    
557
  public boolean isSolved()
558
    {
559
    int index = CUBITS[0].mQuatIndex;
560

    
561
    for(int i=1; i<NUM_CUBITS; i++)
562
      {
563
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
564
      }
565

    
566
    return true;
567
    }
568

    
569
///////////////////////////////////////////////////////////////////////////////////////////////////
570
// only needed for solvers - there are no Bandaged solvers ATM)
571

    
572
  public String retObjectString()
573
    {
574
    return "";
575
    }
576
}
(18-18/37)