~djfun/+junk/UbuntuPhoneAkari

« back to all changes in this revision

Viewing changes to lib/javascript/solver.js

  • Committer: Martin Kaistra
  • Date: 2013-03-07 23:23:02 UTC
  • Revision ID: martin@djfun.de-20130307232302-brnfj8t1ttnn5zlt
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
  @fileOverview Lösen eines Spielbrettes.
 
3
  @requires data_structure.js
 
4
  @author Martin Kaistra, Duc-Hien Tran
 
5
*/
 
6
/**
 
7
  Gibt für das angegebene Feld die angrenzenden leeren Felder zurück.
 
8
  @param {Integer} inLine Zeilennummer des Feldes
 
9
  @param {Integer} inColumn Spaltennummer des Feldes
 
10
  @return {Array}
 
11
*/
 
12
Board.prototype.getSurroundingFreeFields = function(inLine, inColumn) {
 
13
  var freeFields = [];
 
14
  var line, field, column;
 
15
  // nach unten
 
16
  if (inLine < this.size - 1) {
 
17
    line = inLine + 1;
 
18
    field = this.board_modified[line][inColumn];
 
19
    if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
20
      freeFields[freeFields.length] = {"line": line, "column": inColumn, "field": field, "direction": "bottom"};
 
21
    }
 
22
  }
 
23
  // nach oben
 
24
  if (inLine > 0) {
 
25
    line = inLine - 1;
 
26
    field = this.board_modified[line][inColumn];
 
27
    if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
28
      freeFields[freeFields.length] = {"line": line, "column": inColumn, "field": field, "direction": "top"};
 
29
    }
 
30
  }
 
31
  // nach links
 
32
  if (inColumn > 0) {
 
33
    column = inColumn - 1;
 
34
    field = this.board_modified[inLine][column];
 
35
    if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
36
      freeFields[freeFields.length] = {"line": inLine, "column": column, "field": field, "direction": "left"};
 
37
    }
 
38
  }
 
39
  // nach rechts
 
40
  if (inColumn < this.size - 1) {
 
41
    column = inColumn + 1;
 
42
    field = this.board_modified[inLine][column];
 
43
    if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
44
      freeFields[freeFields.length] = {"line": inLine, "column": column, "field": field, "direction": "right"};
 
45
    }
 
46
  }
 
47
  return freeFields;
 
48
};
 
49
/**
 
50
  Gibt für das angegebene Feld zurück, wieviele Felder beleuchtet werden
 
51
  würden, wenn eine Glühbirne dort gesetzt werden würde.
 
52
  @param {Integer} inLine Zeilennummer des Feldes
 
53
  @param {Integer} inColumn Spaltennummer des Feldes
 
54
  @return {Integer}
 
55
*/
 
56
Board.prototype.getLightableFields = function(inLine, inColumn) {
 
57
  
 
58
  var count = 0;
 
59
  var line, field, column;
 
60
  
 
61
  field = this.board_modified[inLine][inColumn];
 
62
  if (field.type == EMPTY && !field.lit) {
 
63
    count = 1;
 
64
    //--
 
65
    line = inLine;
 
66
    column = inColumn;
 
67
    // nach unten
 
68
    if (inLine + 1 < this.size) {
 
69
      while(line + 1 < this.size && this.board_modified[line + 1][column].type != BLACK) {
 
70
        line++;
 
71
        if (!this.board_modified[line][column].lit) {
 
72
          count++;
 
73
        }
 
74
      }
 
75
    }
 
76
    
 
77
    line = inLine;
 
78
    column = inColumn;
 
79
    // nach oben
 
80
    if (inLine - 1 >= 0) {
 
81
      while(line - 1 >= 0 && this.board_modified[line - 1][column].type != BLACK) {
 
82
        line--;
 
83
        if (!this.board_modified[line][column].lit) {
 
84
          count++;
 
85
        }
 
86
      }
 
87
    }
 
88
    
 
89
    line = inLine;
 
90
    column = inColumn;
 
91
    // nach links
 
92
    if (inColumn - 1 >= 0){
 
93
      while(column - 1 >= 0 && this.board_modified[line][column - 1].type != BLACK) {
 
94
        column--;
 
95
        if (!this.board_modified[line][column].lit) {
 
96
          count++;
 
97
        }
 
98
      }
 
99
    }
 
100
    line = inLine;
 
101
    column = inColumn;
 
102
    // nach rechts
 
103
    if (inColumn + 1 < this.size){
 
104
      while(column + 1 < this.size && this.board_modified[line][column + 1].type != BLACK) {
 
105
        column++;
 
106
        if (!this.board_modified[line][column].lit) {
 
107
          count++;
 
108
        }
 
109
      }
 
110
    }
 
111
  }
 
112
  return count;
 
113
};
 
114
/**
 
115
  Gibt für das angegebene Feld die größte angrenzende Zahl zurück.
 
116
  @param {Integer} inLine Zeilennummer des Feldes
 
117
  @param {Integer} inColumn Spaltennummer des Feldes
 
118
  @return {Integer}
 
119
*/
 
120
Board.prototype.getMaxSurroundingNumber = function(inLine, inColumn) {
 
121
  var maxModNumber = 0;
 
122
  var modNumber = 0;
 
123
  if (!this.isOutside(inLine - 1, inColumn)) {
 
124
    if (this.board_modified[inLine - 1][inColumn].type == BLACK &&
 
125
      this.board_modified[inLine - 1][inColumn].number != NO_NUMBER) {
 
126
      modNumber = this.board_modified[inLine - 1][inColumn].modified_number;
 
127
      maxModNumber = maxModNumber < modNumber ? modNumber : maxModNumber;
 
128
    }
 
129
  }
 
130
  if (!this.isOutside(inLine + 1, inColumn)) {
 
131
    if (this.board_modified[inLine + 1][inColumn].type == BLACK &&
 
132
      this.board_modified[inLine + 1][inColumn].number != NO_NUMBER) {
 
133
      modNumber = this.board_modified[inLine + 1][inColumn].modified_number;
 
134
      maxModNumber = maxModNumber < modNumber ? modNumber : maxModNumber;
 
135
    }
 
136
  }
 
137
  if (!this.isOutside(inLine, inColumn - 1)) {
 
138
    if (this.board_modified[inLine][inColumn - 1].type == BLACK &&
 
139
      this.board_modified[inLine][inColumn - 1].number != NO_NUMBER) {
 
140
      modNumber = this.board_modified[inLine][inColumn - 1].modified_number;
 
141
      maxModNumber = maxModNumber < modNumber ? modNumber : maxModNumber;
 
142
    }
 
143
  }
 
144
  if (!this.isOutside(inLine, inColumn + 1)) {
 
145
    if (this.board_modified[inLine][inColumn + 1].type == BLACK &&
 
146
      this.board_modified[inLine][inColumn + 1].number != NO_NUMBER) {
 
147
      modNumber = this.board_modified[inLine][inColumn + 1].modified_number;
 
148
      maxModNumber = maxModNumber < modNumber ? modNumber : maxModNumber;
 
149
    }
 
150
  }
 
151
  return maxModNumber;
 
152
};
 
153
/**
 
154
  Berechnet die minimale Differenz zwischen Zahlen der umgebenden Felder und der Anzahl der freien umgebenden Felder
 
155
  @param {Integer} inLine Zeilennummer des Feldes
 
156
  @param {Integer} inColumn Spaltennummer des Feldes
 
157
  @return {Integer}
 
158
*/
 
159
Board.prototype.getMinSurroundingNumberDifference = function(inLine, inColumn) {
 
160
  var minDifNumber = 4; // smallest number of (Free fields - modNumber)
 
161
  var freeFieldsNumber = 0;
 
162
  var modNumber = 0;
 
163
  if (!this.isOutside(inLine - 1, inColumn)) {
 
164
    if (this.board_modified[inLine - 1][inColumn].type == BLACK &&
 
165
      this.board_modified[inLine - 1][inColumn].number != NO_NUMBER) {
 
166
      modNumber = this.board_modified[inLine - 1][inColumn].modified_number - 3;
 
167
      freeFieldsNumber = this.getNumberSurroundingFreeFields(inLine - 1, inColumn);
 
168
      minDifNumber = minDifNumber < (freeFieldsNumber - modNumber) ? minDifNumber : (freeFieldsNumber - modNumber);
 
169
    }
 
170
  }
 
171
  if (!this.isOutside(inLine + 1, inColumn)) {
 
172
    if (this.board_modified[inLine + 1][inColumn].type == BLACK &&
 
173
      this.board_modified[inLine + 1][inColumn].number != NO_NUMBER) {
 
174
      modNumber = this.board_modified[inLine + 1][inColumn].modified_number - 3;
 
175
      freeFieldsNumber = this.getNumberSurroundingFreeFields(inLine + 1, inColumn);
 
176
      minDifNumber = minDifNumber < (freeFieldsNumber - modNumber) ? minDifNumber : (freeFieldsNumber - modNumber);
 
177
    }
 
178
  }
 
179
  if (!this.isOutside(inLine, inColumn - 1)) {
 
180
    if (this.board_modified[inLine][inColumn - 1].type == BLACK &&
 
181
      this.board_modified[inLine][inColumn - 1].number != NO_NUMBER) {
 
182
      modNumber = this.board_modified[inLine][inColumn - 1].modified_number - 3;
 
183
      freeFieldsNumber = this.getNumberSurroundingFreeFields(inLine, inColumn - 1);
 
184
      minDifNumber = minDifNumber < (freeFieldsNumber - modNumber) ? minDifNumber : (freeFieldsNumber - modNumber);
 
185
    }
 
186
  }
 
187
  if (!this.isOutside(inLine, inColumn + 1)) {
 
188
    if (this.board_modified[inLine][inColumn + 1].type == BLACK &&
 
189
      this.board_modified[inLine][inColumn + 1].number != NO_NUMBER) {
 
190
      modNumber = this.board_modified[inLine][inColumn + 1].modified_number  - 3;
 
191
      freeFieldsNumber = this.getNumberSurroundingFreeFields(inLine, inColumn + 1);
 
192
      minDifNumber = minDifNumber <= (freeFieldsNumber - modNumber) ? minDifNumber : (freeFieldsNumber - modNumber);
 
193
    }
 
194
  }
 
195
  return minDifNumber;
 
196
};
 
197
/**
 
198
  Gibt für das angegebene Feld die Anzahl der angrenzenden freien Felder zurück.
 
199
  @param {Integer} inLine Zeilennummer des Feldes
 
200
  @param {Integer} inColumn Spaltennummer des Feldes
 
201
  @return {Integer}
 
202
*/
 
203
Board.prototype.getNumberSurroundingFreeFields = function(inLine, inColumn) {
 
204
  var freefieldsnumber = 0;
 
205
  // nach unten
 
206
  if (inLine < this.size - 1) {
 
207
    line = inLine + 1;
 
208
    field = this.board_modified[line][inColumn];
 
209
    if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
210
      freefieldsnumber++;
 
211
    }
 
212
  }
 
213
  // nach oben
 
214
  if (inLine > 0) {
 
215
    line = inLine - 1;
 
216
    field = this.board_modified[line][inColumn];
 
217
    if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
218
      freefieldsnumber++;
 
219
    }
 
220
  }
 
221
  // nach links
 
222
  if (inColumn > 0) {
 
223
    column = inColumn - 1;
 
224
    field = this.board_modified[inLine][column];
 
225
    if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
226
      freefieldsnumber++;
 
227
    }
 
228
  }
 
229
  // nach rechts
 
230
  if (inColumn < this.size - 1) {
 
231
    column = inColumn + 1;
 
232
    field = this.board_modified[inLine][column];
 
233
    if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
234
      freefieldsnumber++;
 
235
    }
 
236
  }
 
237
  return freefieldsnumber;
 
238
};
 
239
 
 
240
/**
 
241
  Gibt für das angegebene Feld zurück, ob dort keine Glühbirne gesetzt
 
242
  werden kann. Prüft auch, ob das Feld innerhalb des Spielbretts liegt.
 
243
  @param {Integer} inLine Zeilennummer des Feldes
 
244
  @param {Integer} inColumn Spaltennummer des Feldes
 
245
  @return {Boolean}
 
246
*/
 
247
Board.prototype.isInvalidToSetLightbulb = function(inLine, inColumn){
 
248
    var field;
 
249
    if (inLine < 0 || inLine > this.size - 1 || inColumn < 0 || inColumn > this.size - 1) {
 
250
//        console.log("field is outside of board " + inLine + " " + inColumn);
 
251
        return true;
 
252
    }else{
 
253
      field = this.board_modified[inLine][inColumn];
 
254
    }
 
255
    if(field.type != EMPTY || field.flag == IS_X || field.lit){
 
256
//      console.log("NOT empty" + inLine + " " + inColumn);
 
257
      return true;
 
258
    }
 
259
//  console.log("empty");
 
260
  return false;
 
261
};
 
262
 
 
263
/**
 
264
  Gibt für das angegebene Feld zurück, ob es außerhalb des Spielbretts liegt.
 
265
  @param {Integer} inLine Zeilennummer des Feldes
 
266
  @param {Integer} inColumn Spaltennummer des Feldes
 
267
  @return {Boolean}
 
268
*/
 
269
Board.prototype.isOutside = function(inLine, inColumn) {   // is outside ?
 
270
  if (inLine < 0 || inLine > this.size - 1 || inColumn < 0 || inColumn > this.size - 1) {
 
271
//    console.log("field is outside of board " + inLine + " " + inColumn);
 
272
    return true;
 
273
  }else{
 
274
    return false;
 
275
  }
 
276
};
 
277
 
 
278
/**
 
279
  Gibt für das angegebene Feld zurück, ob es leer ist. Es darf aber beleuchtet oder
 
280
  mit einem x belegt sein.
 
281
  @param {Integer} inLine Zeilennummer des Feldes
 
282
  @param {Integer} inColumn Spaltennummer des Feldes
 
283
  @return {Boolean}
 
284
*/
 
285
Board.prototype.isEmpty = function(inLine, inColumn) {   // do not care of X or lightened
 
286
  var field;
 
287
  if (!this.isOutside(inLine, inColumn)) {
 
288
    field = this.board_modified[inLine][inColumn];
 
289
    if (field.type == EMPTY){
 
290
      return true;
 
291
    }
 
292
  }
 
293
  return false;
 
294
};
 
295
 
 
296
 
 
297
 
 
298
/**
 
299
  Versucht das Spielbrett mit verschiedenen logischen Methoden zu lösen.
 
300
*/
 
301
Board.prototype.solve = function() {
 
302
  var self = this;
 
303
  var solve_methods = {
 
304
    1: this.solve_method1.bind(self),
 
305
    2: this.solve_method2.bind(self),
 
306
    3: this.solve_method3.bind(self),
 
307
    4: this.solve_method4.bind(self),
 
308
    5: this.solve_method5.bind(self),
 
309
    6: this.solve_method6.bind(self),
 
310
    7: this.solve_method7.bind(self),
 
311
    8: this.solve_method8.bind(self),
 
312
    9: this.solve_method9.bind(self),
 
313
    10: this.solve_method10.bind(self),
 
314
    11: this.solve_method11.bind(self),
 
315
    12: this.solve_method12.bind(self),
 
316
    13: this.solve_method13.bind(self),
 
317
    14: this.solve_method14.bind(self),
 
318
    15: this.solve_method15.bind(self),
 
319
    16: this.solve_method16.bind(self),
 
320
    17: this.solve_method17.bind(self),
 
321
    18: this.solve_method18.bind(self)
 
322
  };
 
323
  var methodPointer = 1;
 
324
  var counter = 0;
 
325
  while (methodPointer <= 18 && counter < 1000) {
 
326
    var modified = false;
 
327
    for (var i = 0; i<this.size; i++) {
 
328
      for (var j = 0; j<this.size; j++) {
 
329
        modified = modified || solve_methods[methodPointer](i, j);
 
330
      }
 
331
    }
 
332
    if (modified) {
 
333
      this.solution_properties.classic_methods[methodPointer] = true;
 
334
      methodPointer = 2;
 
335
    } else {
 
336
      methodPointer++;
 
337
    }
 
338
    counter++;
 
339
  }
 
340
  // console.log("Counter: " + counter);
 
341
};
 
342
/**
 
343
  Lösungsmethode 1:
 
344
  Ein 4er-Feld.
 
345
  @param {Integer} inLine Zeilennummer des Feldes
 
346
  @param {Integer} inColumn Spaltennummer des Feldes
 
347
  @return {Boolean}
 
348
*/
 
349
Board.prototype.solve_method1 = function(inLine, inColumn) {
 
350
  var field = this.board_modified[inLine][inColumn];
 
351
  if (field.type == BLACK && field.modified_number == FOUR) {
 
352
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
353
    if (freeFields.length > 0) { // something else should not happen
 
354
      for(var i in freeFields) {
 
355
        this.setLightbulb(freeFields[i].line, freeFields[i].column);
 
356
      }
 
357
      return true;
 
358
    }
 
359
  }
 
360
  return false;
 
361
};
 
362
/**
 
363
  Lösungsmethode 2:
 
364
  Ein 0er-Feld.
 
365
  @param {Integer} inLine Zeilennummer des Feldes
 
366
  @param {Integer} inColumn Spaltennummer des Feldes
 
367
  @return {Boolean}
 
368
*/
 
369
Board.prototype.solve_method2 = function(inLine, inColumn) {
 
370
  var field = this.board_modified[inLine][inColumn];
 
371
  if (field.type == BLACK && field.modified_number == ZERO) {
 
372
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
373
    if (freeFields.length > 0) {
 
374
      for(var i in freeFields) {
 
375
        this.setX(freeFields[i].line, freeFields[i].column);
 
376
      }
 
377
      return true;
 
378
    }
 
379
  }
 
380
  return false;
 
381
};
 
382
/**
 
383
  Lösungsmethode 3:
 
384
  Ein 3er-Feld mit 3 angrenzenden freien Feldern.
 
385
  @param {Integer} inLine Zeilennummer des Feldes
 
386
  @param {Integer} inColumn Spaltennummer des Feldes
 
387
  @return {Boolean}
 
388
*/
 
389
Board.prototype.solve_method3 = function(inLine, inColumn) {
 
390
  var field = this.board_modified[inLine][inColumn];
 
391
  if (field.type == BLACK && field.modified_number == THREE) {
 
392
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
393
    if (freeFields.length == 3) {
 
394
      for(var i in freeFields) {
 
395
        this.setLightbulb(freeFields[i].line, freeFields[i].column);
 
396
      }
 
397
      return true;
 
398
    }
 
399
  }
 
400
  return false;
 
401
};
 
402
/**
 
403
  Lösungsmethode 4:
 
404
  Ein 3er-Feld mit 4 angrenzenden freien Feldern.
 
405
  @param {Integer} inLine Zeilennummer des Feldes
 
406
  @param {Integer} inColumn Spaltennummer des Feldes
 
407
  @return {Boolean}
 
408
*/
 
409
Board.prototype.solve_method4 = function(inLine, inColumn) {
 
410
  var field = this.board_modified[inLine][inColumn];
 
411
  if (field.type == BLACK && field.modified_number == THREE) {
 
412
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
413
    if (freeFields.length == 4) {
 
414
      if ((this.board_modified[inLine - 1][inColumn - 1].flag == IS_X ||
 
415
          this.board_modified[inLine - 1][inColumn - 1].type != EMPTY) &&
 
416
        (this.board_modified[inLine + 1][inColumn - 1].flag == IS_X ||
 
417
          this.board_modified[inLine + 1][inColumn - 1].type != EMPTY) &&
 
418
        (this.board_modified[inLine - 1][inColumn + 1].flag == IS_X ||
 
419
          this.board_modified[inLine - 1][inColumn + 1].type != EMPTY) &&
 
420
        (this.board_modified[inLine + 1][inColumn + 1].flag == IS_X ||
 
421
          this.board_modified[inLine + 1][inColumn + 1].type != EMPTY)) {
 
422
        return false;
 
423
      }
 
424
      this.setX(inLine - 1, inColumn - 1);
 
425
      this.setX(inLine + 1, inColumn - 1);
 
426
      this.setX(inLine - 1, inColumn + 1);
 
427
      this.setX(inLine + 1, inColumn + 1);
 
428
      return true;
 
429
    }
 
430
  }
 
431
  return false;
 
432
};
 
433
/**
 
434
  Lösungsmethode 5:
 
435
  Ein 2er-Feld mit 2 angrenzenden freien Feldern.
 
436
  @param {Integer} inLine Zeilennummer des Feldes
 
437
  @param {Integer} inColumn Spaltennummer des Feldes
 
438
  @return {Boolean}
 
439
*/
 
440
Board.prototype.solve_method5 = function(inLine, inColumn) {
 
441
  var field = this.board_modified[inLine][inColumn];
 
442
  if (field.type == BLACK && field.modified_number == TWO) {
 
443
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
444
    if (freeFields.length == 2) {
 
445
      for(var i in freeFields) {
 
446
        this.setLightbulb(freeFields[i].line, freeFields[i].column);
 
447
      }
 
448
      return true;
 
449
    }
 
450
  }
 
451
  return false;
 
452
};
 
453
/**
 
454
  Lösungsmethode 6:
 
455
  Ein 2er-Feld mit 3 angrenzenden freien Feldern.
 
456
  @param {Integer} inLine Zeilennummer des Feldes
 
457
  @param {Integer} inColumn Spaltennummer des Feldes
 
458
  @return {Boolean}
 
459
*/
 
460
Board.prototype.solve_method6 = function(inLine, inColumn) {
 
461
  var field = this.board_modified[inLine][inColumn];
 
462
  if (field.type == BLACK && field.modified_number == TWO) {
 
463
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
464
    if (freeFields.length == 3) {
 
465
      var dir_top = false;
 
466
      var dir_bottom = false;
 
467
      var dir_left = false;
 
468
      var dir_right = false;
 
469
      for(var i in freeFields) {
 
470
        if (freeFields[i].direction == "top") {
 
471
          dir_top = true;
 
472
        } else if (freeFields[i].direction == "bottom") {
 
473
          dir_bottom = true;
 
474
        } else if (freeFields[i].direction == "left") {
 
475
          dir_left = true;
 
476
        } else if (freeFields[i].direction == "right") {
 
477
          dir_right = true;
 
478
        }
 
479
      }
 
480
      if (!dir_top) {
 
481
        if ((this.board_modified[inLine + 1][inColumn - 1].flag == IS_X ||
 
482
          this.board_modified[inLine + 1][inColumn - 1].type != EMPTY) &&
 
483
          (this.board_modified[inLine + 1][inColumn + 1].flag == IS_X ||
 
484
          this.board_modified[inLine + 1][inColumn + 1].type != EMPTY)) {
 
485
          return false;
 
486
        }
 
487
        this.setX(inLine + 1, inColumn - 1);
 
488
        this.setX(inLine + 1, inColumn + 1);
 
489
      } else if (!dir_bottom) {
 
490
        if ((this.board_modified[inLine - 1][inColumn - 1].flag == IS_X ||
 
491
          this.board_modified[inLine - 1][inColumn - 1].type != EMPTY) &&
 
492
          (this.board_modified[inLine - 1][inColumn + 1].flag == IS_X ||
 
493
          this.board_modified[inLine - 1][inColumn + 1].type != EMPTY)) {
 
494
          return false;
 
495
        }
 
496
        this.setX(inLine - 1, inColumn - 1);
 
497
        this.setX(inLine - 1, inColumn + 1);
 
498
      } else if (!dir_left) {
 
499
        if ((this.board_modified[inLine - 1][inColumn + 1].flag == IS_X ||
 
500
          this.board_modified[inLine - 1][inColumn + 1].type != EMPTY) &&
 
501
          (this.board_modified[inLine + 1][inColumn + 1].flag == IS_X ||
 
502
          this.board_modified[inLine + 1][inColumn + 1].type != EMPTY)) {
 
503
          return false;
 
504
        }
 
505
        this.setX(inLine - 1, inColumn + 1);
 
506
        this.setX(inLine + 1, inColumn + 1);
 
507
      } else if (!dir_right) {
 
508
        if ((this.board_modified[inLine - 1][inColumn - 1].flag == IS_X ||
 
509
          this.board_modified[inLine - 1][inColumn - 1].type != EMPTY) &&
 
510
          (this.board_modified[inLine + 1][inColumn - 1].flag == IS_X ||
 
511
          this.board_modified[inLine + 1][inColumn - 1].type != EMPTY)) {
 
512
          return false;
 
513
        }
 
514
        this.setX(inLine - 1, inColumn - 1);
 
515
        this.setX(inLine + 1, inColumn - 1);
 
516
      }
 
517
      if (DEBUG) {
 
518
        console.log(inLine + "/" + inColumn);
 
519
      }
 
520
      return true;
 
521
    }
 
522
  }
 
523
  return false;
 
524
};
 
525
/**
 
526
  Lösungsmethode 7:
 
527
  Ein 1er-Feld mit 1 angrenzenden freien Feldern.
 
528
  @param {Integer} inLine Zeilennummer des Feldes
 
529
  @param {Integer} inColumn Spaltennummer des Feldes
 
530
  @return {Boolean}
 
531
*/
 
532
Board.prototype.solve_method7 = function(inLine, inColumn) {
 
533
  var field = this.board_modified[inLine][inColumn];
 
534
  if (field.type == BLACK && field.modified_number == ONE) {
 
535
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
536
    if (freeFields.length == 1) {
 
537
      for(var i in freeFields) {
 
538
        this.setLightbulb(freeFields[i].line, freeFields[i].column);
 
539
      }
 
540
      return true;
 
541
    }
 
542
  }
 
543
  return false;
 
544
};
 
545
/**
 
546
  Lösungsmethode 8:
 
547
  Ein 1er-Feld mit 2 angrenzenden freien Feldern.
 
548
  @param {Integer} inLine Zeilennummer des Feldes
 
549
  @param {Integer} inColumn Spaltennummer des Feldes
 
550
  @return {Boolean}
 
551
*/
 
552
Board.prototype.solve_method8 = function(inLine, inColumn) {
 
553
  var field = this.board_modified[inLine][inColumn];
 
554
  if (field.type == BLACK && field.modified_number == ONE) {
 
555
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
556
    if (freeFields.length == 2) {
 
557
      var dir_top = false;
 
558
      var dir_bottom = false;
 
559
      var dir_left = false;
 
560
      var dir_right = false;
 
561
      for(var i in freeFields) {
 
562
        if (freeFields[i].direction == "top") {
 
563
          dir_top = true;
 
564
        } else if (freeFields[i].direction == "bottom") {
 
565
          dir_bottom = true;
 
566
        } else if (freeFields[i].direction == "left") {
 
567
          dir_left = true;
 
568
        } else if (freeFields[i].direction == "right") {
 
569
          dir_right = true;
 
570
        }
 
571
      }
 
572
      if (dir_top && dir_left) {
 
573
        if (this.board_modified[inLine - 1][inColumn - 1].flag == IS_X ||
 
574
          this.board_modified[inLine - 1][inColumn - 1].type != EMPTY) {
 
575
          return false;
 
576
        }
 
577
        this.setX(inLine - 1, inColumn - 1);
 
578
        return true;
 
579
      } else if (dir_top && dir_right) {
 
580
        if (this.board_modified[inLine - 1][inColumn + 1].flag == IS_X ||
 
581
          this.board_modified[inLine - 1][inColumn + 1].type != EMPTY) {
 
582
          return false;
 
583
        }
 
584
        this.setX(inLine - 1, inColumn + 1);
 
585
        return true;
 
586
      } else if (dir_right && dir_bottom) {
 
587
        if (this.board_modified[inLine + 1][inColumn + 1].flag == IS_X ||
 
588
          this.board_modified[inLine + 1][inColumn + 1].type != EMPTY) {
 
589
          return false;
 
590
        }
 
591
        this.setX(inLine + 1, inColumn + 1);
 
592
        return true;
 
593
      } else if (dir_bottom && dir_left) {
 
594
        if (this.board_modified[inLine + 1][inColumn - 1].flag == IS_X ||
 
595
          this.board_modified[inLine + 1][inColumn - 1].type != EMPTY) {
 
596
          return false;
 
597
        }
 
598
        this.setX(inLine + 1, inColumn - 1);
 
599
        return true;
 
600
      }
 
601
      return false;
 
602
    }
 
603
  }
 
604
  return false;
 
605
};
 
606
/**
 
607
  Lösungsmethode 9:
 
608
  Ein Feld was nur genau durch sich selbst beleuchten werden kann.
 
609
  @param {Integer} inLine Zeilennummer des Feldes
 
610
  @param {Integer} inColumn Spaltennummer des Feldes
 
611
  @return {Boolean}
 
612
*/
 
613
Board.prototype.solve_method9 = function(inLine, inColumn) {
 
614
  var field = this.board_modified[inLine][inColumn];
 
615
  var line, column;
 
616
  if (field.type == EMPTY && !field.lit && (field.flag != IS_X)) {
 
617
    //--
 
618
    line = inLine;
 
619
    column = inColumn;
 
620
    // nach unten
 
621
    if (inLine + 1 < this.size) {
 
622
      while(line + 1 < this.size && this.board_modified[line + 1][column].type != BLACK) {
 
623
        line++;
 
624
        if (!this.board_modified[line][column].lit &&
 
625
            this.board_modified[line][column].flag != IS_X) {
 
626
          return false;
 
627
        }
 
628
      }
 
629
    }
 
630
    
 
631
    line = inLine;
 
632
    column = inColumn;
 
633
    // nach oben
 
634
    if (inLine - 1 >= 0) {
 
635
      while(line - 1 >= 0 && this.board_modified[line - 1][column].type != BLACK) {
 
636
        line--;
 
637
        if (!this.board_modified[line][column].lit &&
 
638
            this.board_modified[line][column].flag != IS_X) {
 
639
          return false;
 
640
        }
 
641
      }
 
642
    }
 
643
    
 
644
    line = inLine;
 
645
    column = inColumn;
 
646
    // nach links
 
647
    if (inColumn - 1 >= 0){
 
648
      while(column - 1 >= 0 && this.board_modified[line][column - 1].type != BLACK) {
 
649
        column--;
 
650
        if (!this.board_modified[line][column].lit &&
 
651
            this.board_modified[line][column].flag != IS_X) {
 
652
          return false;
 
653
        }
 
654
      }
 
655
    }
 
656
    line = inLine;
 
657
    column = inColumn;
 
658
    // nach rechts
 
659
    if (inColumn + 1 < this.size){
 
660
      while(column + 1 < this.size && this.board_modified[line][column + 1].type != BLACK) {
 
661
        column++;
 
662
        if (!this.board_modified[line][column].lit &&
 
663
            this.board_modified[line][column].flag != IS_X) {
 
664
          return false;
 
665
        }
 
666
      }
 
667
    }
 
668
    //--
 
669
    this.setLightbulb(inLine, inColumn);
 
670
    return true;
 
671
  }
 
672
  return false;
 
673
};
 
674
/**
 
675
  Lösungsmethode 10:
 
676
  Ein Feld, was nur genau von einem anderen beleuchtet werden kann.
 
677
  @param {Integer} inLine Zeilennummer des Feldes
 
678
  @param {Integer} inColumn Spaltennummer des Feldes
 
679
  @return {Boolean}
 
680
*/
 
681
Board.prototype.solve_method10 = function(inLine, inColumn) {
 
682
  var found = false;
 
683
  var emptyFieldLine;
 
684
  var emptyFieldColumn;
 
685
  var line, column;
 
686
  
 
687
  var field = this.board_modified[inLine][inColumn];
 
688
  if (field.type == EMPTY && !field.lit && (field.flag == IS_X)) {
 
689
    //--
 
690
    line = inLine;
 
691
    column = inColumn;
 
692
    // nach unten
 
693
    if (inLine + 1 < this.size) {
 
694
      while(line + 1 < this.size && this.board_modified[line + 1][column].type != BLACK) {
 
695
        line++;
 
696
        if (!this.board_modified[line][column].lit &&
 
697
            this.board_modified[line][column].flag != IS_X) {
 
698
          if (found) {
 
699
            return false;
 
700
          } else {
 
701
            found = true;
 
702
            emptyFieldLine = line;
 
703
            emptyFieldColumn = column;
 
704
          }
 
705
        }
 
706
      }
 
707
    }
 
708
    
 
709
    line = inLine;
 
710
    column = inColumn;
 
711
    // nach oben
 
712
    if (inLine - 1 >= 0) {
 
713
      while(line - 1 >= 0 && this.board_modified[line - 1][column].type != BLACK) {
 
714
        line--;
 
715
        if (!this.board_modified[line][column].lit &&
 
716
            this.board_modified[line][column].flag != IS_X) {
 
717
          if (found) {
 
718
            return false;
 
719
          } else {
 
720
            found = true;
 
721
            emptyFieldLine = line;
 
722
            emptyFieldColumn = column;
 
723
          }
 
724
        }
 
725
      }
 
726
    }
 
727
    
 
728
    line = inLine;
 
729
    column = inColumn;
 
730
    // nach links
 
731
    if (inColumn - 1 >= 0){
 
732
      while(column - 1 >= 0 && this.board_modified[line][column - 1].type != BLACK) {
 
733
        column--;
 
734
        if (!this.board_modified[line][column].lit &&
 
735
            this.board_modified[line][column].flag != IS_X) {
 
736
          if (found) {
 
737
            return false;
 
738
          } else {
 
739
            found = true;
 
740
            emptyFieldLine = line;
 
741
            emptyFieldColumn = column;
 
742
          }
 
743
        }
 
744
      }
 
745
    }
 
746
    line = inLine;
 
747
    column = inColumn;
 
748
    // nach rechts
 
749
    if (inColumn + 1 < this.size){
 
750
      while(column + 1 < this.size && this.board_modified[line][column + 1].type != BLACK) {
 
751
        column++;
 
752
        if (!this.board_modified[line][column].lit &&
 
753
            this.board_modified[line][column].flag != IS_X) {
 
754
          if (found) {
 
755
            return false;
 
756
          } else {
 
757
            found = true;
 
758
            emptyFieldLine = line;
 
759
            emptyFieldColumn = column;
 
760
          }
 
761
        }
 
762
      }
 
763
    }
 
764
    //--
 
765
    if (!found) {
 
766
      return false;
 
767
    }
 
768
    this.setLightbulb(emptyFieldLine, emptyFieldColumn);
 
769
    return true;
 
770
  }
 
771
  return false;
 
772
};
 
773
/**
 
774
  Lösungsmethode 11:
 
775
  Ein 2er-Feld mit 3 angrenzenden freien Feldern. (siehe planung.txt)
 
776
  @param {Integer} inLine Zeilennummer des Feldes
 
777
  @param {Integer} inColumn Spaltennummer des Feldes
 
778
  @return {Boolean}
 
779
*/
 
780
Board.prototype.solve_method11 = function(inLine, inColumn) {
 
781
  var field = this.board_modified[inLine][inColumn];
 
782
  if (field.type == BLACK && field.modified_number == TWO) {
 
783
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
784
    if (freeFields.length == 3) {
 
785
      var dir_top = false;
 
786
      var dir_bottom = false;
 
787
      var dir_left = false;
 
788
      var dir_right = false;
 
789
      for(var i in freeFields) {
 
790
        if (freeFields[i].direction == "top") {
 
791
          dir_top = true;
 
792
        } else if (freeFields[i].direction == "bottom") {
 
793
          dir_bottom = true;
 
794
        } else if (freeFields[i].direction == "left") {
 
795
          dir_left = true;
 
796
        } else if (freeFields[i].direction == "right") {
 
797
          dir_right = true;
 
798
        }
 
799
      }
 
800
      if (!dir_top) {
 
801
        if ((this.board_modified[inLine + 1][inColumn - 1].type == BLACK &&
 
802
          this.board_modified[inLine + 1][inColumn - 1].modified_number == ONE)) {
 
803
          this.setLightbulb(inLine, inColumn + 1);
 
804
          this.setX(inLine + 1, inColumn - 2);
 
805
          this.setX(inLine + 2, inColumn - 1);
 
806
          return true;
 
807
        }
 
808
        if ((this.board_modified[inLine + 1][inColumn + 1].type == BLACK &&
 
809
          this.board_modified[inLine + 1][inColumn + 1].modified_number == ONE)) {
 
810
          this.setLightbulb(inLine, inColumn - 1);
 
811
          this.setX(inLine + 1, inColumn + 2);
 
812
          this.setX(inLine + 2, inColumn + 1);
 
813
          return true;
 
814
        }
 
815
      } else if (!dir_bottom) {
 
816
        if ((this.board_modified[inLine - 1][inColumn - 1].type == BLACK &&
 
817
          this.board_modified[inLine - 1][inColumn - 1].modified_number == ONE)) {
 
818
          this.setLightbulb(inLine, inColumn + 1);
 
819
          this.setX(inLine - 1, inColumn - 2);
 
820
          this.setX(inLine - 2, inColumn - 1);
 
821
          return true;
 
822
        }
 
823
        if ((this.board_modified[inLine - 1][inColumn + 1].type == BLACK &&
 
824
          this.board_modified[inLine - 1][inColumn + 1].modified_number == ONE)) {
 
825
          this.setLightbulb(inLine, inColumn - 1);
 
826
          this.setX(inLine - 1, inColumn + 2);
 
827
          this.setX(inLine - 2, inColumn + 1);
 
828
          return true;
 
829
        }
 
830
      } else if (!dir_left) {
 
831
        if ((this.board_modified[inLine - 1][inColumn + 1].type == BLACK &&
 
832
          this.board_modified[inLine - 1][inColumn + 1].modified_number == ONE)) {
 
833
          this.setLightbulb(inLine + 1, inColumn);
 
834
          this.setX(inLine - 1, inColumn + 2);
 
835
          this.setX(inLine - 2, inColumn + 1);
 
836
          return true;
 
837
        }
 
838
        if ((this.board_modified[inLine + 1][inColumn + 1].type == BLACK &&
 
839
          this.board_modified[inLine + 1][inColumn + 1].modified_number == ONE)) {
 
840
          this.setLightbulb(inLine - 1, inColumn);
 
841
          this.setX(inLine + 1, inColumn + 2);
 
842
          this.setX(inLine + 2, inColumn + 1);
 
843
          return true;
 
844
        }
 
845
      } else if (!dir_right) {
 
846
        if ((this.board_modified[inLine - 1][inColumn - 1].type == BLACK &&
 
847
          this.board_modified[inLine - 1][inColumn - 1].modified_number == ONE)) {
 
848
          this.setLightbulb(inLine + 1, inColumn);
 
849
          this.setX(inLine - 1, inColumn - 2);
 
850
          this.setX(inLine - 2, inColumn - 1);
 
851
          return true;
 
852
        }
 
853
        if ((this.board_modified[inLine + 1][inColumn - 1].type == BLACK &&
 
854
          this.board_modified[inLine + 1][inColumn - 1].modified_number == ONE)) {
 
855
          this.setLightbulb(inLine - 1, inColumn);
 
856
          this.setX(inLine + 1, inColumn - 2);
 
857
          this.setX(inLine + 2, inColumn - 1);
 
858
          return true;
 
859
        }
 
860
      }
 
861
    }
 
862
  }
 
863
  return false;
 
864
};
 
865
/**
 
866
  Lösungsmethode 12:
 
867
  Ein 3er-Feld mit 4 angrenzenden freien Feldern. (siehe planung.txt)
 
868
  @param {Integer} inLine Zeilennummer des Feldes
 
869
  @param {Integer} inColumn Spaltennummer des Feldes
 
870
  @return {Boolean}
 
871
*/
 
872
Board.prototype.solve_method12 = function(inLine, inColumn) {
 
873
  var field = this.board_modified[inLine][inColumn];
 
874
  if (field.type == BLACK && field.modified_number == THREE) {
 
875
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
876
    if (freeFields.length == 4) {
 
877
      if ((this.board_modified[inLine - 1][inColumn - 1].type == BLACK &&
 
878
          this.board_modified[inLine - 1][inColumn - 1].modified_number == ONE)) {
 
879
        this.setLightbulb(inLine, inColumn + 1);
 
880
        this.setLightbulb(inLine + 1, inColumn);
 
881
        this.setX(inLine - 1, inColumn - 2);
 
882
        this.setX(inLine - 2, inColumn - 1);
 
883
        return true;
 
884
      }
 
885
      if ((this.board_modified[inLine - 1][inColumn + 1].type == BLACK &&
 
886
          this.board_modified[inLine - 1][inColumn + 1].modified_number == ONE)) {
 
887
        this.setLightbulb(inLine, inColumn - 1);
 
888
        this.setLightbulb(inLine + 1, inColumn);
 
889
        this.setX(inLine - 1, inColumn + 2);
 
890
        this.setX(inLine - 2, inColumn + 1);
 
891
        return true;
 
892
      }
 
893
      if ((this.board_modified[inLine + 1][inColumn - 1].type == BLACK &&
 
894
          this.board_modified[inLine + 1][inColumn - 1].modified_number == ONE)) {
 
895
        this.setLightbulb(inLine, inColumn + 1);
 
896
        this.setLightbulb(inLine - 1, inColumn);
 
897
        this.setX(inLine + 1, inColumn - 2);
 
898
        this.setX(inLine + 2, inColumn - 1);
 
899
        return true;
 
900
      }
 
901
      if ((this.board_modified[inLine + 1][inColumn + 1].type == BLACK &&
 
902
          this.board_modified[inLine + 1][inColumn + 1].modified_number == ONE)) {
 
903
        this.setLightbulb(inLine, inColumn - 1);
 
904
        this.setLightbulb(inLine - 1, inColumn);
 
905
        this.setX(inLine + 1, inColumn + 2);
 
906
        this.setX(inLine + 2, inColumn + 1);
 
907
        return true;
 
908
      }
 
909
    }
 
910
  }
 
911
  return false;
 
912
};
 
913
/**
 
914
  Lösungsmethode 13:
 
915
  Ein 2er-Feld, das an ein anderes 2er-Feld direkt angrenzt.
 
916
  @param {Integer} inLine Zeilennummer des Feldes
 
917
  @param {Integer} inColumn Spaltennummer des Feldes
 
918
  @return {Boolean}
 
919
*/
 
920
Board.prototype.solve_method13 = function(inLine, inColumn) {
 
921
  var field = this.board_modified[inLine][inColumn];
 
922
  if (field.type == BLACK && field.modified_number == TWO) {
 
923
    if ((inLine > 0 && this.board_modified[inLine - 1][inColumn].type == BLACK &&
 
924
        this.board_modified[inLine - 1][inColumn].modified_number == TWO)) {
 
925
      this.setLightbulb(inLine - 2, inColumn); //zwei 2er am Rand nebeneinander ist unloesbar
 
926
      this.setLightbulb(inLine + 1, inColumn);
 
927
      return true;
 
928
    }
 
929
    if ((inColumn > 0 && this.board_modified[inLine][inColumn - 1].type == BLACK &&
 
930
        this.board_modified[inLine][inColumn - 1].modified_number == TWO)) {
 
931
      this.setLightbulb(inLine, inColumn - 2);
 
932
      this.setLightbulb(inLine, inColumn + 1);
 
933
      return true;
 
934
    }
 
935
  }
 
936
  return false;
 
937
};
 
938
/**
 
939
  Lösungsmethode 14:
 
940
  Ein freies Feld mit 2 gegenüberliegenden angrenzenden 3er-Feldern.
 
941
  @param {Integer} inLine Zeilennummer des Feldes
 
942
  @param {Integer} inColumn Spaltennummer des Feldes
 
943
  @return {Boolean}
 
944
*/
 
945
Board.prototype.solve_method14 = function(inLine, inColumn) {
 
946
  if (inLine > 0 && inLine < this.size - 1 && inColumn > 0 && inColumn < this.size - 1) {
 
947
    var field = this.board_modified[inLine][inColumn];
 
948
    if (field.type == EMPTY && field.flag != IS_X && !field.lit) {
 
949
      if ((this.board_modified[inLine][inColumn - 1].type == EMPTY &&
 
950
          !this.board_modified[inLine][inColumn - 1].lit) &&
 
951
          (this.board_modified[inLine][inColumn + 1].type == EMPTY &&
 
952
          !this.board_modified[inLine][inColumn + 1].lit) &&
 
953
          (this.board_modified[inLine - 1][inColumn].type == BLACK &&
 
954
          this.board_modified[inLine - 1][inColumn].modified_number == THREE) &&
 
955
          (this.board_modified[inLine + 1][inColumn].type == BLACK &&
 
956
          this.board_modified[inLine + 1][inColumn].modified_number == THREE)) {
 
957
        this.setLightbulb(inLine, inColumn);
 
958
        this.setLightbulb(inLine - 2, inColumn);
 
959
        this.setLightbulb(inLine + 2, inColumn);
 
960
        return true;
 
961
      }
 
962
      if ((this.board_modified[inLine - 1][inColumn].type == EMPTY &&
 
963
          !this.board_modified[inLine - 1][inColumn].lit) &&
 
964
          (this.board_modified[inLine + 1][inColumn].type == EMPTY &&
 
965
          !this.board_modified[inLine + 1][inColumn].lit) &&
 
966
          (this.board_modified[inLine][inColumn - 1].type == BLACK &&
 
967
          this.board_modified[inLine][inColumn - 1].modified_number == THREE) &&
 
968
          (this.board_modified[inLine][inColumn + 1].type == BLACK &&
 
969
          this.board_modified[inLine][inColumn + 1].modified_number == THREE)) {
 
970
        this.setLightbulb(inLine, inColumn);
 
971
        this.setLightbulb(inLine, inColumn - 2);
 
972
        this.setLightbulb(inLine, inColumn + 2);
 
973
        return true;
 
974
      }
 
975
    }
 
976
  }
 
977
  return false;
 
978
};
 
979
/**
 
980
  Lösungsmethode 15:
 
981
  Ein 1er-Feld mit 2 angrenzenden freien Feldern. (siehe planung.txt)
 
982
  @param {Integer} inLine Zeilennummer des Feldes
 
983
  @param {Integer} inColumn Spaltennummer des Feldes
 
984
  @return {Boolean}
 
985
*/
 
986
Board.prototype.solve_method15 = function(inLine, inColumn) {
 
987
  //console.log("solve_method15");
 
988
  var return_flag1 = false;
 
989
  var return_flag2 = false;
 
990
  var field = this.board_modified[inLine][inColumn];
 
991
  if (field.type == BLACK && field.modified_number == ONE) {
 
992
    var freeFields = this.getSurroundingFreeFields(inLine, inColumn);
 
993
    if (freeFields.length == 2) {
 
994
      var dir_top = false;
 
995
      var dir_bottom = false;
 
996
      var dir_left = false;
 
997
      var dir_right = false;
 
998
      for(var i in freeFields) {
 
999
        if (freeFields[i].direction == "top") {
 
1000
          dir_top = true;
 
1001
        } else if (freeFields[i].direction == "bottom") {
 
1002
          dir_bottom = true;
 
1003
        } else if (freeFields[i].direction == "left") {
 
1004
          dir_left = true;
 
1005
        } else if (freeFields[i].direction == "right") {
 
1006
          dir_right = true;
 
1007
        }
 
1008
      }
 
1009
      if (dir_top && dir_left) {
 
1010
        if (this.board_modified[inLine - 1][inColumn - 1].type == BLACK &&
 
1011
          this.board_modified[inLine - 1][inColumn - 1].modified_number == ONE) {
 
1012
          return_flag1 = this.setX(inLine - 2, inColumn - 1);
 
1013
          return_flag2 = this.setX(inLine - 1, inColumn - 2);
 
1014
          return (return_flag1 || return_flag2);
 
1015
        }
 
1016
      } else if (dir_top && dir_right) {
 
1017
        if (this.board_modified[inLine - 1][inColumn + 1].type == BLACK &&
 
1018
          this.board_modified[inLine - 1][inColumn + 1].modified_number == ONE) {
 
1019
          return_flag1 = this.setX(inLine - 1, inColumn + 2);
 
1020
          return_flag2 = this.setX(inLine - 2, inColumn + 1);
 
1021
          return (return_flag1 || return_flag2);
 
1022
        }
 
1023
      } else if (dir_right && dir_bottom) {
 
1024
        if (this.board_modified[inLine + 1][inColumn + 1].type == BLACK &&
 
1025
          this.board_modified[inLine + 1][inColumn + 1].modified_number == ONE) {
 
1026
          return_flag1 = this.setX(inLine + 1, inColumn + 2);
 
1027
          return_flag2 = this.setX(inLine + 2, inColumn + 1);
 
1028
          return (return_flag1 || return_flag2);
 
1029
        }
 
1030
      } else if (dir_bottom && dir_left) {
 
1031
        if (this.board_modified[inLine + 1][inColumn - 1].type == BLACK &&
 
1032
          this.board_modified[inLine + 1][inColumn - 1].modified_number == ONE) {
 
1033
            return_flag1 = this.setX(inLine + 1, inColumn - 2);
 
1034
            return_flag2 = this.setX(inLine + 2, inColumn - 1);
 
1035
          return (return_flag1 || return_flag2);
 
1036
        }
 
1037
      }
 
1038
      return false;
 
1039
    }
 
1040
  }
 
1041
  return false;
 
1042
};
 
1043
/**
 
1044
  Lösungsmethode 16:
 
1045
  Ein freies Feld mit 2 gegenüberliegenden angrenzenden 2er-Feldern.
 
1046
  @param {Integer} inLine Zeilennummer des Feldes
 
1047
  @param {Integer} inColumn Spaltennummer des Feldes
 
1048
  @return {Boolean}
 
1049
*/
 
1050
Board.prototype.solve_method16 = function(inLine, inColumn) {
 
1051
  var field = this.board_modified[inLine][inColumn];
 
1052
  if (inLine > 0 && inLine < this.size - 1) {
 
1053
    if (!this.isInvalidToSetLightbulb(inLine, inColumn)) { // looking for valid field.
 
1054
      if ((this.board_modified[inLine - 1][inColumn].type == BLACK &&  // is top a 2-field?
 
1055
        this.board_modified[inLine - 1][inColumn].modified_number == TWO) &&
 
1056
        (this.board_modified[inLine + 1][inColumn].type == BLACK && // is bottom a 2-field?
 
1057
        this.board_modified[inLine + 1][inColumn].modified_number == TWO)){
 
1058
        if (this.isInvalidToSetLightbulb(inLine - 2, inColumn) || this.isInvalidToSetLightbulb(inLine + 2, inColumn)){ // is top or bottom of 2-field invalid ?
 
1059
          if (this.isEmpty(inLine, inColumn - 1) == this.isEmpty(inLine, inColumn + 1)){  // are left and right fields the same type?
 
1060
            this.setLightbulb(inLine, inColumn);
 
1061
            return true;
 
1062
          }
 
1063
        }else if (this.isOutside(inLine, inColumn - 1) || this.isOutside(inLine, inColumn + 1)) {
 
1064
            this.setLightbulb(inLine, inColumn);
 
1065
          return true;
 
1066
        }
 
1067
      }
 
1068
    }
 
1069
  }
 
1070
  if(inColumn > 0 && inColumn < this.size - 1){
 
1071
    if (!this.isInvalidToSetLightbulb(inLine, inColumn)) { // looking for valid field.
 
1072
      if ((this.board_modified[inLine][inColumn - 1].type == BLACK &&  // is left a 2-field?
 
1073
        this.board_modified[inLine][inColumn - 1].modified_number == TWO) &&
 
1074
        (this.board_modified[inLine][inColumn + 1].type == BLACK && // is right a 2-field?
 
1075
        this.board_modified[inLine][inColumn + 1].modified_number == TWO)){
 
1076
        if (this.isInvalidToSetLightbulb(inLine, inColumn  - 2) || this.isInvalidToSetLightbulb(inLine, inColumn  + 2)){ // is left or right of 2-field invalid ?
 
1077
          if (this.isEmpty(inLine - 1, inColumn) == this.isEmpty(inLine + 1, inColumn)){  // are top and bottom fields the same type?
 
1078
            this.setLightbulb(inLine, inColumn);
 
1079
            return true;
 
1080
          }
 
1081
        }else if (this.isOutside(inLine  - 1, inColumn) || this.isOutside(inLine + 1, inColumn)) {
 
1082
            this.setLightbulb(inLine, inColumn);
 
1083
          return true;
 
1084
        }
 
1085
      }
 
1086
    }
 
1087
  }
 
1088
  return false;
 
1089
};
 
1090
/**
 
1091
  Lösungsmethode 17:
 
1092
  Ein freies Feld mit 2 gegenüberliegenden angrenzenden Feldern; einmal 1er und einmal 3er.
 
1093
  @param {Integer} inLine Zeilennummer des Feldes
 
1094
  @param {Integer} inColumn Spaltennummer des Feldes
 
1095
  @return {Boolean}
 
1096
*/
 
1097
Board.prototype.solve_method17 = function(inLine, inColumn) {
 
1098
  if (inLine > 0 && inLine < this.size - 1 && inColumn > 0 && inColumn < this.size - 1) {
 
1099
    var field = this.board_modified[inLine][inColumn];
 
1100
    if (!this.isInvalidToSetLightbulb(inLine, inColumn)) { // looking for valid field?
 
1101
      if ((this.board_modified[inLine - 1][inColumn].type == BLACK &&  // is top a 3-field?
 
1102
        this.board_modified[inLine - 1][inColumn].modified_number == THREE) &&
 
1103
        (this.board_modified[inLine + 1][inColumn].type == BLACK && // is bottom a 1-field?
 
1104
        this.board_modified[inLine + 1][inColumn].modified_number == ONE)){
 
1105
        if (this.isInvalidToSetLightbulb(inLine + 2, inColumn)){ // is bottom of 1-field invalid ?
 
1106
          //console.log(inLine + " : " + inColumn);
 
1107
          if (this.isEmpty(inLine, inColumn - 1) == this.isEmpty(inLine, inColumn + 1)){  // are left and right fields the same type?
 
1108
            this.setLightbulb(inLine, inColumn);
 
1109
            return true;
 
1110
          }
 
1111
        }
 
1112
      }
 
1113
    }
 
1114
    if (!this.isInvalidToSetLightbulb(inLine, inColumn)) { // looking for valid field?
 
1115
      if ((this.board_modified[inLine - 1][inColumn].type == BLACK &&  // is top a 1-field?
 
1116
        this.board_modified[inLine - 1][inColumn].modified_number == ONE) &&
 
1117
        (this.board_modified[inLine + 1][inColumn].type == BLACK && // is bottom a 3-field?
 
1118
        this.board_modified[inLine + 1][inColumn].modified_number == THREE)){
 
1119
        if (this.isInvalidToSetLightbulb(inLine - 2, inColumn)){ // is top of 1-field invalid ?
 
1120
          //console.log(inLine + " : " + inColumn);
 
1121
          if (this.isEmpty(inLine, inColumn - 1) == this.isEmpty(inLine, inColumn + 1)){  // are left and right fields the same type?
 
1122
            this.setLightbulb(inLine, inColumn);
 
1123
            return true;
 
1124
          }
 
1125
        }
 
1126
      }
 
1127
    }
 
1128
    if (!this.isInvalidToSetLightbulb(inLine, inColumn)) { // looking for valid field?
 
1129
      if ((this.board_modified[inLine][inColumn - 1].type == BLACK &&  // is left a 3-field?
 
1130
        this.board_modified[inLine][inColumn - 1].modified_number == THREE) &&
 
1131
        (this.board_modified[inLine][inColumn + 1].type == BLACK && // is right a 1-field?
 
1132
        this.board_modified[inLine][inColumn + 1].modified_number == ONE)){
 
1133
        if (this.isInvalidToSetLightbulb(inLine, inColumn + 2)){ // is right of 1-field invalid ?
 
1134
          //console.log(inLine + " : " + inColumn);
 
1135
          if (this.isEmpty(inLine - 1, inColumn) == this.isEmpty(inLine  + 1, inColumn)){  // are left and right fields the same type?
 
1136
            this.setLightbulb(inLine, inColumn);
 
1137
            return true;
 
1138
          }
 
1139
        }
 
1140
      }
 
1141
    }
 
1142
    if (!this.isInvalidToSetLightbulb(inLine, inColumn)) { // looking for valid field?
 
1143
      if ((this.board_modified[inLine][inColumn - 1].type == BLACK &&  // is left a 1-field?
 
1144
        this.board_modified[inLine][inColumn - 1].modified_number == ONE) &&
 
1145
        (this.board_modified[inLine][inColumn + 1].type == BLACK && // is right a 3-field?
 
1146
        this.board_modified[inLine][inColumn + 1].modified_number == THREE)){
 
1147
        if (this.isInvalidToSetLightbulb(inLine, inColumn - 2)){ // is left of 1-field invalid ?
 
1148
          //console.log(inLine + " : " + inColumn);
 
1149
          if (this.isEmpty(inLine  - 1, inColumn) == this.isEmpty(inLine  + 1, inColumn)){  // are left and right fields the same type?
 
1150
            this.setLightbulb(inLine, inColumn);
 
1151
            return true;
 
1152
          }
 
1153
        }
 
1154
      }
 
1155
    }
 
1156
  }
 
1157
  return false;
 
1158
};
 
1159
/**
 
1160
  Lösungsmethode 18:
 
1161
  Ein Feld mit x, das von genau 2 anderen Feldern beleuchtet werden kann.
 
1162
  @param {Integer} inLine Zeilennummer des Feldes
 
1163
  @param {Integer} inColumn Spaltennummer des Feldes
 
1164
  @return {Boolean}
 
1165
*/
 
1166
Board.prototype.solve_method18 = function(inLine, inColumn) {
 
1167
  var found = 0;
 
1168
  var emptyFieldOneLine;
 
1169
  var emptyFieldOneColumn;
 
1170
  var emptyFieldTwoLine;
 
1171
  var emptyFieldTwoColumn;
 
1172
  
 
1173
  var probFieldLine;
 
1174
  var probFieldColumn;
 
1175
  var line, column;
 
1176
  
 
1177
  var field = this.board_modified[inLine][inColumn];
 
1178
  if (field.type == EMPTY && !field.lit && (field.flag == IS_X)) {
 
1179
    //--
 
1180
    line = inLine;
 
1181
    column = inColumn;
 
1182
    // nach unten
 
1183
    if (inLine + 1 < this.size) {
 
1184
      while(line + 1 < this.size && this.board_modified[line + 1][column].type != BLACK) {
 
1185
        line++;
 
1186
        if (!this.board_modified[line][column].lit &&
 
1187
            this.board_modified[line][column].flag != IS_X) {
 
1188
          if (found >= 2) {
 
1189
            return false;
 
1190
          } else if (found === 0) {
 
1191
            emptyFieldOneLine = line;
 
1192
            emptyFieldOneColumn = column;
 
1193
          } else if (found == 1) {
 
1194
            emptyFieldTwoLine = line;
 
1195
            emptyFieldTwoColumn = column;
 
1196
          }
 
1197
          found++;
 
1198
        }
 
1199
      }
 
1200
    }
 
1201
    
 
1202
    line = inLine;
 
1203
    column = inColumn;
 
1204
    // nach oben
 
1205
    if (inLine - 1 >= 0) {
 
1206
      while(line - 1 >= 0 && this.board_modified[line - 1][column].type != BLACK) {
 
1207
        line--;
 
1208
        if (!this.board_modified[line][column].lit &&
 
1209
            this.board_modified[line][column].flag != IS_X) {
 
1210
          if (found >= 2) {
 
1211
            return false;
 
1212
          } else if (found === 0) {
 
1213
            emptyFieldOneLine = line;
 
1214
            emptyFieldOneColumn = column;
 
1215
          } else if (found == 1) {
 
1216
            emptyFieldTwoLine = line;
 
1217
            emptyFieldTwoColumn = column;
 
1218
          }
 
1219
          found++;
 
1220
        }
 
1221
      }
 
1222
    }
 
1223
    
 
1224
    line = inLine;
 
1225
    column = inColumn;
 
1226
    // nach links
 
1227
    if (inColumn - 1 >= 0){
 
1228
      while(column - 1 >= 0 && this.board_modified[line][column - 1].type != BLACK) {
 
1229
        column--;
 
1230
        if (!this.board_modified[line][column].lit &&
 
1231
            this.board_modified[line][column].flag != IS_X) {
 
1232
          if (found >= 2) {
 
1233
            return false;
 
1234
          } else if (found === 0) {
 
1235
            emptyFieldOneLine = line;
 
1236
            emptyFieldOneColumn = column;
 
1237
          } else if (found == 1) {
 
1238
            emptyFieldTwoLine = line;
 
1239
            emptyFieldTwoColumn = column;
 
1240
          }
 
1241
          found++;
 
1242
        }
 
1243
      }
 
1244
    }
 
1245
    line = inLine;
 
1246
    column = inColumn;
 
1247
    // nach rechts
 
1248
    if (inColumn + 1 < this.size){
 
1249
      while(column + 1 < this.size && this.board_modified[line][column + 1].type != BLACK) {
 
1250
        column++;
 
1251
        if (!this.board_modified[line][column].lit &&
 
1252
            this.board_modified[line][column].flag != IS_X) {
 
1253
          if (found >= 2) {
 
1254
            return false;
 
1255
          } else if (found === 0) {
 
1256
            emptyFieldOneLine = line;
 
1257
            emptyFieldOneColumn = column;
 
1258
          } else if (found == 1) {
 
1259
            emptyFieldTwoLine = line;
 
1260
            emptyFieldTwoColumn = column;
 
1261
          }
 
1262
          found++;
 
1263
        }
 
1264
      }
 
1265
    }
 
1266
    //--
 
1267
    if (found <= 1) {
 
1268
      return false;
 
1269
    }
 
1270
    if (emptyFieldOneLine == emptyFieldTwoLine || emptyFieldOneColumn == emptyFieldTwoColumn) {
 
1271
      return false;
 
1272
    }
 
1273
    probFieldLine = (emptyFieldOneLine == inLine) ? emptyFieldTwoLine : emptyFieldOneLine;
 
1274
    probFieldColumn = (emptyFieldOneColumn == inColumn) ? emptyFieldTwoColumn : emptyFieldOneColumn;
 
1275
    
 
1276
    this.setLightbulb(probFieldLine, probFieldColumn);
 
1277
    if (this.board_modified[emptyFieldOneLine][emptyFieldOneColumn].lit &&
 
1278
        this.board_modified[emptyFieldTwoLine][emptyFieldTwoColumn].lit) {
 
1279
      this.removeLightbulb(probFieldLine, probFieldColumn);
 
1280
      this.setX(probFieldLine, probFieldColumn);
 
1281
      return true;
 
1282
    }
 
1283
    this.removeLightbulb(probFieldLine, probFieldColumn);
 
1284
 
 
1285
  }
 
1286
  return false;
 
1287
};
 
1288
 
 
1289
Board.MAX_RECUR = 10;
 
1290
Board.prototype.recur_counter = 0;
 
1291
Board.backtrackingversion = 0;
 
1292
 
 
1293
/**
 
1294
  Versucht das Spielbrett mit Backtracking zusätzlich zu
 
1295
  den logischen Methoden zu lösen.
 
1296
  @param {Integer} recur Rekursionsstufe
 
1297
  @return {Integer} Anzahl der gefundenen Lösungen
 
1298
*/
 
1299
Board.prototype.solve_backtracking = function (recur) {
 
1300
  this.recur_counter++;
 
1301
  if (recur > Board.MAX_RECUR) {
 
1302
    return -1;
 
1303
  }
 
1304
  this.solution_properties.max_recur = recur;
 
1305
      
 
1306
  var selectedField;
 
1307
  var selectedField1;
 
1308
  
 
1309
  this.solve();
 
1310
  if (DEBUG) {
 
1311
    this.consoleOut();
 
1312
  }
 
1313
  if (DEBUG) {
 
1314
    console.log("====== Version 1." + Board.backtrackingversion + " ======");
 
1315
  }
 
1316
 
 
1317
  if (this.isWon()) {
 
1318
    if (DEBUG) {
 
1319
      console.log("Gewonnen auf Stufe " + recur);
 
1320
      this.consoleOut();
 
1321
      console.log("------------------------------------------");
 
1322
    }
 
1323
    // save last solution
 
1324
    this.solution = this.copyBoard();
 
1325
    return 1;
 
1326
  }
 
1327
    
 
1328
  // Select new field to try:
 
1329
  var maxN = 0;
 
1330
  var maxModNumber = 0;
 
1331
  var minDifNumber = 4;
 
1332
  
 
1333
  outer: for (var i = 0; i<this.size; i++) {
 
1334
    for (var j = 0; j<this.size; j++) {
 
1335
      var field = this.board_modified[i][j];
 
1336
      if (field.type == EMPTY && !field.lit && field.flag != IS_X) {
 
1337
        if (Board.backtrackingversion === 0){
 
1338
          if (this.getMaxSurroundingNumber(i, j) > maxModNumber) {
 
1339
            maxModNumber = this.getMaxSurroundingNumber(i, j);
 
1340
            selectedField = {line: i, column: j};
 
1341
            // console.log(i + "/" + j);
 
1342
            // break outer;
 
1343
          }
 
1344
        }else{
 
1345
          if (this.getMinSurroundingNumberDifference(i, j) < minDifNumber) {
 
1346
            minDifNumber = this.getMinSurroundingNumberDifference(i, j);
 
1347
            selectedField = {line: i, column: j};
 
1348
            // console.log(i + "/" + j);
 
1349
            // break outer;
 
1350
          }
 
1351
        }
 
1352
        if (this.getLightableFields(i, j) > maxN) {
 
1353
          maxN = this.getLightableFields(i, j);
 
1354
          selectedField1 = {line: i, column: j};
 
1355
        }
 
1356
      }
 
1357
    }
 
1358
  }
 
1359
  selectedField = selectedField ? selectedField : selectedField1;
 
1360
  if (!selectedField) {
 
1361
    // console.log("no free field found");
 
1362
    return 0;
 
1363
  }
 
1364
  if (DEBUG) {
 
1365
    console.log(maxN + " auf Stufe " + recur + ": " + selectedField.line + "/" + selectedField.column);
 
1366
  }
 
1367
  
 
1368
  // try as X and then as LIGHTBULB
 
1369
  var boardCopy = this.copyBoard();
 
1370
  
 
1371
  this.setX(selectedField.line, selectedField.column);
 
1372
  var solvedAsX = this.solve_backtracking(recur + 1);
 
1373
  
 
1374
  if (solvedAsX > 1) {
 
1375
    return solvedAsX;
 
1376
  }
 
1377
  
 
1378
  this.rollbackBoard(boardCopy);
 
1379
  
 
1380
  this.setLightbulb(selectedField.line, selectedField.column);
 
1381
  var solvedAsLightbulb = this.solve_backtracking(recur + 1);
 
1382
  if (solvedAsLightbulb < 0 && solvedAsX < 0) {
 
1383
    return -1;
 
1384
  } else if (solvedAsX <= 0) {
 
1385
    return solvedAsLightbulb;
 
1386
  } else if (solvedAsLightbulb <= 0) {
 
1387
    return solvedAsX;
 
1388
  } else {
 
1389
    return solvedAsX + solvedAsLightbulb;
 
1390
  }
 
1391
};
 
 
b'\\ No newline at end of file'