55
55
--size=i : length side of the board (default: #{ BOARD_SIZE } )
56
56
--planes=i : the total number of planes (default: #{ PLANES_NUM } )
57
57
--wrap! : wrap the plane around the play board (default: #{ wrap_plane } )
58
+ --head=s : character used for the head of the plane (default: "#{ head_char } ")
58
59
--hit=s : character used when a plane is hit (default: "#{ hit_char } ")
59
60
--miss=s : character used when a plane is missed (default: "#{ miss_char } ")
60
61
--colors! : use ANSI colors (requires Term::ANSIColor) (default: #{ use_colors } )
@@ -79,15 +80,15 @@ func ver {
79
80
}
80
81
81
82
if ( ARGV ) {
82
- var getopt = (
83
- try { frequire ( 'Getopt::Long' ) }
84
- catch { STDERR . print ( "Can't load the 'Getopt::Long' Perl module...\n " ) ; Sys . exit ( 2 ) }
85
- )
83
+ var getopt =
84
+ try { frequire ( 'Getopt::Long' ) }
85
+ catch { STDERR . print ( "Can't load the 'Getopt::Long' Perl module...\n " ) ; Sys . exit ( 2 ) }
86
86
87
87
getopt . GetOptions (
88
88
'board-size|size=i' => func ( _ , v ) { BOARD_SIZE = Num ( v ) } ,
89
89
'planes-num=i' => func ( _ , v ) { PLANES_NUM = Num ( v ) } ,
90
90
'seed=i' => func ( _ , v ) { seed = Num ( v ) } ,
91
+ 'head-char=s' => func ( _ , v ) { head_char = Str ( v ) } ,
91
92
'hit-char=s' => func ( _ , v ) { hit_char = Str ( v ) } ,
92
93
'miss-char=s' => func ( _ , v ) { miss_char = Str ( v ) } ,
93
94
'wrap!' => func ( _ , v ) { wrap_plane = Bool ( v ) } ,
@@ -195,8 +196,8 @@ func print_ascii_table(*boards) {
195
196
var t = table . drawit
196
197
197
198
if ( defined ( ANSI ) && use_colors ) {
198
- t . gsub! ( hit_char , ANSI . colored ( hit_char , 'bold red' ) )
199
- t . gsub! ( miss_char , ANSI . colored ( miss_char , 'yellow' ) )
199
+ t . gsub! ( HIT , ANSI . colored ( hit_char , 'bold red' ) )
200
+ t . gsub! ( AIR , ANSI . colored ( miss_char , 'yellow' ) )
200
201
t . gsub! ( HEAD , ANSI . colored ( head_char , 'bold green' ) )
201
202
}
202
203
@@ -208,15 +209,24 @@ func print_ascii_table(*boards) {
208
209
}
209
210
}
210
211
211
- func valid_assignment ( play_board , info_board ) {
212
+ func valid_assignment ( play_board , info_board , extra = false ) {
212
213
213
214
[ play_board , info_board ] . zip { |*rows |
214
215
rows . zip { |play , info |
216
+
215
217
if ( info == AIR ) {
216
218
if ( play != BLANK ) {
217
219
return false
218
220
}
219
221
}
222
+ elsif ( extra ) {
223
+
224
+ info == BLANK && next
225
+
226
+ if ( info != play ) {
227
+ return false
228
+ }
229
+ }
220
230
}
221
231
}
222
232
@@ -333,56 +343,37 @@ func get_letters() {
333
343
return letters
334
344
}
335
345
336
- func valid ( play_board , info_board ) {
337
-
338
- [ play_board , info_board ] . zip { |*rows |
339
- rows . zip { |play , info |
340
-
341
- info == BLANK && next
342
-
343
- if ( info == AIR ) {
344
- if ( play != BLANK ) {
345
- return false
346
- }
347
- }
348
- elsif ( info != play ) {
349
- return false
350
- }
351
- }
352
- }
353
-
354
- return true
355
- }
356
-
357
346
func solve ( callback ) {
358
347
359
348
var tries = 0
360
- var info_board = BOARD_SIZE . of { BOARD_SIZE . of { BLANK } }
349
+ var info_board = make_play_board ( )
361
350
var boards = make_play_boards ( info_board )
362
351
363
352
loop {
364
353
for board , plane_count in ( boards ) {
365
354
366
355
var play_board = board . dclone
367
356
guess ( info_board , play_board , plane_count ) || next
368
- valid ( play_board , info_board ) || next
357
+ valid_assignment ( play_board , info_board , true ) || next
369
358
370
359
var all_dead = true
371
360
var new_info = false
372
361
373
- var head_pos = get_head_positions ( play_board ) . shuffle
362
+ # Prefer points nearest to the center of the board
363
+ var head_pos = get_head_positions ( play_board ) . sort_by { |p |
364
+ hypot ( p . map { |i | ( BOARD_SIZE -1 ) /2 - i } ...)
365
+ }
374
366
375
367
head_pos = head_pos . grep_2d { |x , y | info_board [ x ] [ y ] == BLANK } . map_2d { |x , y |
376
- [ x , y , DIRECTIONS . first_by { |d |
377
- ( pointers ( play_board , x , y , d ) . count_by { *_ = = HIT } == 7 ) &&
378
- ( pointers ( info_board , x , y , d ) . none { *_ = = AIR } )
368
+ [ x , y , DIRECTIONS . map { |d | pointers ( info_board , x , y , d ) } . grep { |t |
369
+ t && t . none { *_ = = AIR }
379
370
} ]
380
371
}
381
372
382
373
# Prefer the planes with the most hits
383
374
head_pos = head_pos . sort_by { |p |
384
- pointers ( info_board , p [ 0 ] , p [ 1 ] , p [ 2 ] ) . count_by { *_ = = HIT }
385
- } . flip
375
+ p [ 2 ] . sum_by { | t | t . count_by { *_ = = HIT } } -> neg
376
+ }
386
377
387
378
head_pos . each_2d { |i , j |
388
379
@@ -391,7 +382,7 @@ func solve(callback) {
391
382
}
392
383
393
384
all_dead = false
394
- var score = callback ( i , j , play_board , info_board )
385
+ var score = callback ( i , j , play_board , info_board ) \\ return nil
395
386
396
387
if ( score == BLANK ) {
397
388
score = AIR
@@ -432,13 +423,13 @@ func process_user_input(i, j, play_board, info_board) {
432
423
loop {
433
424
say "=> My guess: #{ indices2letters { i } } #{ j +1 } "
434
425
say "=> Score (hit, head or air)"
435
- var input = ( Sys . scanln ( "> " ) \\ break -> lc )
436
- input ~~ [ 'q' , 'quit' ] && break
426
+ var input = ( Sys . scanln ( "> " ) \\ return nil -> lc )
427
+ input ~~ [ 'q' , 'quit' ] && return nil
437
428
438
429
input . trim!
439
430
440
431
score_table . has ( input ) || do {
441
- say ":: Invalid score..."
432
+ say "\n :: Invalid score...\n "
442
433
next
443
434
}
444
435
@@ -461,5 +452,7 @@ if (simulate) {
461
452
}
462
453
else {
463
454
var tries = solve ( process_user_input )
464
- say "\n :: All planes destroyed in #{ tries } tries!\n "
455
+ if ( defined ( tries ) ) {
456
+ say "\n :: All planes destroyed in #{ tries } tries!\n "
457
+ }
465
458
}
0 commit comments