-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib.sbl
1146 lines (742 loc) · 31.9 KB
/
lib.sbl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
* Copyright 2017, David Shields
* Licensed under the MIT license.
* Library functions.
define('counter(text,count)') :(counter.end)
* Output the descriptive text *text* and value *n* of a counter.
counter
out(lpad(text,26) lpad(count,12)) :(return)
counter.end
define('counters()elapsed') :(counters.end)
* Output the collected counter metrics.
counters
out()
out('Performance metrics :')
* out('Time ',(time() - g.time) / 1000)
* elapsed = (time() - g.time) / 1000
* counter('execution time (sec)' , thousands(elapsed))
counter('turns' , thousands(g.turn))
counter('placements found by scan' , thousands(count.scanned))
counter('permutations examined' , thousands(count.perm))
counter('cells examined' , thousands(count.cells))
counter('potential moves found' , thousands(count.moves ))
counter('lines checked' , thousands(count.checkline))
counter('words checked' , thousands(count.checkword))
counter('cross lines checked' , thousands(count.cline))
counter('valid moves found' , thousands(count.valid))
counter('total inserts' , thousands(count.insert))
counter('contiguous inserts' , thousands(count.insert.contig))
counter('split inserts' , thousands(count.insert.split))
:(return)
counters.end
define('endgame()') :(endgame.end)
* Summarize results at end of game.
endgame
out( name(g.players[1]) ' scored ' number(total(g.players[1])) ' points, '
. 'with a best move of ' cardinal(highest(g.players[1]),'point') '.')
out( name(g.players[2]) ' scored ' number(total(g.players[2])) ' points, '
. 'with a best move of ' cardinal(highest(g.players[2]),' points') '.')
out(gt(thirty(g.players[1])) name(g.players[1]) ' had '
. cardinal(thirty(g.players[1]),'move') ' of thirty or more points.')
out(gt(thirty(g.players[2])) name(g.players[2]) ' had '
. cardinal(thirty(g.players[2]),'move') ' of thirty or more points.')
counters()
:(return)
endgame.end
define('game(mode)players,player,opn,move,i,li,offset,open.word,'
. 'open.score,n,tiles,moves,li,passed,board,lfn'):(game.end)
* Play a game of fribble. *max* is the maximum number of moves.
* Mode is
* one to have fribble play a game with itself,
* two to let you play against fribble, and
* three to work with fribble to play with another person,
* who may be using fribble themself, but good for them!
game
* Test to see if log file needed. Even if not, we always call log()
* function. It will do nothing if no log file. This avoids need
* to test for presence of log file before each call to log().
eq(g.log) :s(game.setup)
* Open log file.
g.logfile.name = datename(g.date) '.fri'
output(.g.logfile,g.logfile.channel,g.logfile.name) :s(game.log)
out('unable to open log file ',g.logfile.name) :(game.setup)
game.log
log('* game ' mode)
log('* version ' g.version)
log('* time.start ' time())
log('* date.start ' g.date)
log.tiles()
log.player(1)
log.player(2)
game.setup
pid = 2;* set to two so will become one when loop first entered
game.turn
g.turn = g.turn + 1
log('turn ' g.turn)
* ne(f.trace) out('g.turn=' g.turn ' g.maxmoves=' g.maxmoves)
gt(g.turn,g.lastmove + 3)
. out('Game over - too many turns with no move.'):s(game.over)
gt(g.turn,g.maxmoves)
. out('Game over -- too many turns ('
. g.maxmoves ').') :s(game.over)
pid = (eq(pid,1) 2, 1)
player = g.players[pid]
ne(kind(player),player.kind.move) out('Move ' number(g.turn) ' for player ' name(player)
. (differ(g.tilemanager) ', with tiles "'
. show.tiles(rack(player),'A'),'') '".')
turn(pid,mode) :f(game.turn.fail)s(game.turn)
game.turn.fail
* Here if turn failed because no move could be found.
* Try to swap three tiles
out('no move, swapping tiles.')
rack(player) = swap(pid,3) :(game.turn)
game.fail
* Here if no move found.
out('No move found.')
* Here if no move found, in which case the return value is
* a set of swapped tiles. If *move* is null, then pass.
differ(move) :s(game.swap)
passed = passed + 1
out(gt(passed,6) ' Too many passed moves.') :s(game.over)
out('Player ' name(player) ' passes.') :(game.turn)
game.swap
out('swapping tiles pid=',pid)
rack(player) = swap(pid,3)
out('Player ' name(player) ' swapped tiles.')
out('Player ' name(player) ' now has tiles '
. show.tiles(rack(player))) :(game.turn)
game.over
endgame()
* Complete log file.
log('* total.1 ' total(g.players[1]))
log('* total.2 ' total(g.players[2]))
log('* date.finis ' date(2))
log('* time.finis ' time())
log('endgame')
differ(logfile) endfile(g.logfile.channel)
:(return)
game.end
define('getrack()') :(getrack.end)
* Read in rack from standard input
getrack
getrack = input :f(freturn)s(return)
getrack.end
define('getlines()i,j,line') :(getlines.end)
* Get lines from standard input, end with first blank line, skip if comment
getlines
getlines = array(30)
line = dupl(' ',15)
getlines.init
getlines[i = i + 1] = line
lt(i,30) :s(getlines.init)
* Here with lines initialized to blank, now read in supplied lines
i = 0
getlines.next
line = input :f(getlines.done)
line '*' :s(getlines.next)
* line ' ' :s(getlines.done)
line break(' ') . i span(' ') =
line = replace(line,'-',' ')
line = rpad(line,15,' ')
* out('getlines i',i)
* out('getlines line',line)
getlines[i] = line
line =
:(getlines.next)
getlines.done
g.board = grid(getlines)
g.lines = lines(g.board)
show.lines(g.lines,'getlines.done')
* Compute g.used from full set of lines
i = 0
getlines.used.line
gt(i = i + 1,30) :s(getlines.finis)
line = g.lines[i]
* Update g.used for this line
j = 0
getlines.used.col
gt(j = j + 1,15) :s(getlines.used.line)
ident(substr(line,j,1),' ') :s(getlines.used.col)
g.used[row(i,j),column(i,j)] = 1
g.bonus[row(i,j),column(i,j)] = 1
:(getlines.used.col)
getlines.finis
out('g.board')
show.grid(g.board)
out('g.used')
show.grid(g.used)
g.bonus.lines = lines(g.bonus)
out('g.bonus')
show.grid(g.bonus)
* &dump = 3
* :(end)
:(return)
getlines.end
define('log.tiles()') :(log.tiles.end)
* Write tiles set to log file
log.tiles
log('tiles "' g.tiles '"') :(return)
log.tiles.end
define('log.player(pid)') :(log.player.end)
* Write player description to log file.
log.player
log('player ' pid ' ' show.player(pid))
:(return)
log.player.end
define('grid(lines,start)i,r,c,line') :(grid.end)
* Construct a grid from a sequence of lines beginning at index *start*,
* (1..15 for rows, 16..30 for columns.
grid
grid = array('15,15',' ')
start = ident(start) +1
start = (le(start,15) 1, 16)
gt(start,15) :s(grid.col)
* Here to build grid from the rows.
r = 0
grid.nextrow
gt(r = r + 1,15) :s(grid.done)
line = lines[r] :f(grid.3)
i = 0
grid.r
* out('grid r ' r ' ' i + 1 ' ' substr(line,i + 1,1))
grid[r,i = i + 1] = substr(line,i,1) :s(grid.r)f(grid.nextrow)
grid.col
* Here to build grid from the columns.
c = 14;* set to c will index first column after entering loop below.
grid.nextcol
gt(c = c + 1,30) :s(grid.done)
line = lines[c]
i = 0
grid.c
grid[i = i + 1,c] = substr(line,i,1) :s(grid.c)f(grid.nextcol)
grid.done :(return)
grid.end
define('lineid(num)') :(lineid.end)
* Returns row or column id corresponding to line number *num*.
lineid
lineid = (le(num,15) 'r' lpad(num,2,0), 'c' lpad(num - 15,2,0)):(return)
lineid.end
define('lines(g)i') :(lines.end)
* Express the grid *g* as a sequence of lines, with the
* first fifteen consisting of the rows and the last
* fifteen consisting of the columns.
lines
lines = array(30)
lines.next
* Make sure all entries in lines are in lower case,
* since we enter moves in g in upper case.
gt(i = i + 1,15) :s(return)
lines[i] = lcase(hline(g,i))
lines[i + 15] = lcase(vline(g,i)) :(lines.next)
lines.end
define('log(text)') :(log.end)
* Write text to logfile if making a log.
log
eq(g.log) :s(return)
g.logfile = text :(return)
log.end
define('m(id,str,text)fi,free,len,pos') :(m.end)
* Create move in line with given id and text.
* *str* is one of the following:
* integer gives starting position, in range 1..15
* string that can be converted to integer, treat as in integer case
* string giving list of empty (open) cells used, with entries
* separated by spaces.
* For example, the following each specify the word 'fribble'
* starting at position 6 in row 8.
* m(r8,6,'fribble')
* m(r8,'6 7 8 9 10 11 12','fribble')
m
free = array(size(text))
* out('m str' str)
str break(' ') :s(m.list)
pos = +str :f(m.error)
m.pos
len = len + 1
* out('pos fi ' fi ' ' pos + (fi - 1 ))
free[fi = fi + 1] = pos + (fi - 1) :s(m.pos)f(m.done)
m.list
* Prepare for m.next loop.
str = str ' '
m.next
str break(' ') . pos span(' ') = :f(m.done)
len = len + 1
free[fi = fi + 1] = pos :(m.next)
m.error
out('m(id,str,text) error - .') :(freturn)
m.done
ne(len, size(text)) out('m size mismatch,try again'):s(freturn)
out('m.done id=' id ' text=' text ', free[1]='
. free[1] ' free[n]=' free[size(text)])
m = move(id,free,text) :(return)
m.end
define('makemove(pid,move)player,board,lines,id') :(makemove.end)
* Make a move for player with id *pid*, and return its value.
makemove
player = g.players[pid]
makemove = move
* out(ne(g.tracing) 'Game move ' show.move(move))
g.lastmove = g.turn
total(player) = total(player) + points(move)
thirty(player) = ge(points(move),30) thirty(player) + 1
highest(player) = gt(points(move),highest(player)) points(move)
playmove(move)
id = lineid(id(move))
out( name(player) ' played "' show.tiles(text(move)) '" for '
. number(points(move)) ' points,'
. ' starting at ' (ident(substr(id,1),'r') 'row ', 'column')
. ' ' number(+substr(id,2))
. ', position ' number(free(move)[1]) '.')
out('Score now : '
. name(g.players[1]) ', ' number(total(g.players[1])) '; '
. name(g.players[2]) ', ' number(total(g.players[2])) '. ')
out('B 4 C 4 D 2 F 4 G 3 H 3 J 10 K 5 L 2 M 4 '
. 'N 2 P 4 Q 10 U 2 V 5 W 4 X 8 Y 3 Z 10 ')
out()
* Display move in grid with just this move in upper case by saving
* the board, playing the move with the text in upper case, showing it,
* and then restoring the board to its saved state.
board = copy (g.board)
lines = copy(g.lines)
text(move) = ucase(text(move))
playmove(move)
text(move) = lcase(text(move));* restore
* show.grid(g.board)
g.board = board
g.lines = lines
* show.lines(g.lines,'Lines')
* show.grid(g.used)
g.used.lines = lines(g.used)
* Update lines affected by grid changes to maintain consistency.
g.bonus.lines = lines(g.bonus)
g.lines = lines(g.board)
* Fold g.lines into lower case so only new moves made later will
* display in upper case.
li = 0
makemove.fold
g.lines[li = li + 1] = lcase(g.lines[li]) :s(makemove.fold)
* Rebuild board since lines have changed.
* out('rebuilding board')
g.board = grid(g.lines)
:(return)
makemove.end
define('move.input()mov,line,out,cells,start,text') :(move.input.end)
* Enter move.inputly (by hand).
move.input
ne(f.trace) out('getting move move.inputly')
* Here to enter the move move.inputly
move.input.in
out('enter move row/column')
start = terminal
out(' you entered ' start)
out()
out('enter cell(s)')
cells = terminal
out(' you entered ' cells)
out()
out('enter text')
text = terminal
out(' you entered ' text)
move.input = 'm(' start ',"' cells '","' text '")'
out()
:(return)
move.input = input.user() :f(end)
:(return)
ident(move.input) :s(return)
move.input ( 'pass' | 'swap' | 'resign' | 'quit') :(return)
move.input = move.input :(return)
move.input = eval(move.input) :f(move.input.error)
* ident(datatype(move.input),'move') out(show.move(move.input)) :f(move.input.error)
ne(g.turn,1) :s(move.input.check)
move.input.check
valid(move.input) :s(return)
out('need to enter a valid move') :(move.input)
move.input.error
out('move.input error evaluating ' line) :(freturn)
move.input.end
define('playmove(move)i,p,r,c,ch') :(playmove.end)
* Play move *move*, updating the board and related objects.
playmove
id = id(move)
* out('enter playmove ' show.move(move))
* out('free ' prototype(free(move)))
playmove.ch
p = free(move)[i = i + 1] :f(playmove.done)
r = row(id,p)
c = column(id,p)
ch = substr(text(move),i,1)
* out('playmove p=' p ' i=' i ' r=' r ' c=' c ' ch=' ch)
g.board[r, c] = ch
* out('playmove r=' r ' c=' c ' char=' g.board[r,c])
g.used[r,c] = 1
g.bonus[r, c] = ' ' :(playmove.ch) ;* indicate bonus no longer available
playmove.done
* out('playmove.done i=' i)
out(ne(g.tracing) 'playmove returns')
:(return)
playmove.end
define('reader(filename)n') :(reader.end)
* Return file as table of lines, with zero-th entry giving number
* of lines.
reader
input(.file,g.channel.temp,filename) :s(reader.opened)
out('unable to open reader file ' filename '.') :(freturn)
reader.opened
n = 0
reader = table(100)
reader.next
reader[n = n + 1] = file :s(reader.next)
* Here at end of file, convert map to array of lines.
reader[0] = n - 1;* line count
endfile(g.channel.temp)
:(return)
reader.end
* One-time initialization for replay()
str = 'date endgame game move play rack tiles total turn version '
replay.ops = table(10)
replay.init
str break(' ') . op ' ' = :f(replay.init.done)
replay.ops[op] = 1 :(replay.init)
replay.init.done
define('replay(option)line,command') :(replay.end)
* Replay commands from previous game.
* If *option* is an integer, replay that number of commands
* from the replay file. If *option* is a string not convertible
* to an integer, prepare for replaying by reading in the lines
* from that file.
replay
g.replay.lines = reader(option) :s(replay.lines)
out('reader returned ' prototype(ops) ' commands.')
out('error reading commands from ' option) :(freturn)
replay.lines
g.replay.i = 0;* set up for replaying.
g.replay.n = commands[0] :(return)
replay.next
gt(g.replay.i = g.replay.i + 1, g.replay.n) :s(replay.done)
line = g.replay.lines[g.replay.i] :f(replay.done)
out('replaying line ' g.replay.i ' |' line '|')
ident(line) :s(replay.next)
line '*' :s(replay.next)
line span(&lcase) . command =
out('replay.op=' command)
differ(replay.ops[command]) :s($('replay.' command))
out('replaying unknown command ' command ', ignore.'):(replay.next)
replay.endgame
:(replay.done)
replay.move
line span(' ') len(1) . pid span(' ') =
out('replay.move evaluating |' line '|')
move = eval(line)
out('replaying move datatype=' datatype(move) ',' show.move(move))
show.play(makemove(pid,move))
:(replay.next)
replay.player
line '.' len(1) . pid span(' ') =
g.players[pid] = eval(line)
:(replay.next)
replay.rack
line '.' len(1) . pid =
line = ' rack(g.players[ ' pid '] = ' line
out('replay.rack ' line)
eval(line)
:(replay.next)
replay.tiles
line = ' g.tiles = ' line
out('replay.tiles ' line)
eval(line)
:(replay.next)
replay.turn
line span(' ') span('0123456789') . turn =
g.turn = turn :s(replay.next)
replay.done
:(return)
replay.end
define('replenish(pid)player,rack,s') :(replenish.end)
* Replenish a player's rack. Do this from the tiles is g.tilemanager is
* set, or get the new tiles from the user otherwise.
replenish
player = g.players[pid]
differ(g.tilemanager) :s(replenish.auto)
replenish.manual
out('enter rack for player : ' show.player(pid))
replenish = lcase(input) :f(replenish.eof)
ident(replenish) out('no input - try again.') :s(replenish.manual)
gt(size(replenish),7) out('too many letters |' replenish
. '|, try again.') :s(replenish.manual)
s = replenish
s span(&lcase) =
differ(s) out('non-alphabetic character - try again.')
. :s(replenish.manual)
:(return)
replenish.eof
out('end of data on input - bye ') :(end)
replenish.auto
replenish = rack(player)
eq(size(replenish),7) :s(return)
replenish = replenish take(7 - size(replenish)) :(return)
replenish.end
define('row(num,pos)') :(row.end)
* Returns row corresponding to position POS in line NUM.
row
row = ((le(num,15) num, pos)) :(return)
row.end
define('shuffle()tiles,n,passes,r1,r2,ch') :(shuffle.end)
* Shuffle the remaining tiles by randomly swapping.players[2]
* tiles several times.
shuffle
tiles = unpack(g.tiles)
n = size(g.tiles)
passes = random(1000) + 500
shuffle.next
le(passes = passes - 1) :s(shuffle.done)
r1 = random(n); r2 = random(n)
eq(r1,r2) :s(shuffle.next)
ch = tiles[r1]
tiles[r1] = tiles[r2]
tiles[r2] = ch :(shuffle.next)
shuffle.done
g.tiles = pack(tiles)
:(return)
shuffle.end
define('state.restore(saved)') :(state.restore.end)
* Restore the state of the game from a prior save.
state.restore
g.grid = saved['grid']
g.bonus = saved['bonus']
g.tiles = saved['tiles']
g.players[1] = saved['player.1']
g.players[2] = saved['player.2']
:(return)
state.restore.end
define('state.save()') :(state.save.end)
* Save the state of the game.
state.save
state.save = table(10)
state.save['grid'] = copy(g.grid)
state.save['bonus'] = copy(g.bonus)
state.save['tiles'] = copy(g.tiles)
state.save['player.1'] = copy(g.players[1])
state.save['player.2'] = copy(g.players[2])
:(return)
state.save.end
define('swap(pid,n)player,tiles') :(swap.end)
* Swap *n* tiles from the first *n* characters in *tiles*
* of player with id *pid*. If fewer than *n* tiles remain,
* set *n* to the size of the tiles.
swap
player = g.players[pid]
tiles = rack(player)
n = gt(n,size(tiles)) size(tiles)
n = gt(n,size(g.tiles)) size(g.tiles)
eq(n) :s(freturn)
swap.next
swap = substr(g.tiles,1,n)
g.tiles = substr(g.tiles,n + 1) substr(tiles,1,n)
:(return)
swap.end
define('take(n)') :(take.end)
* Take *n* tiles from the tiles, or taking all
* the remaining tiles if fewer than *n* remain.
take
n = gt(n,size(g.tiles)) size(g.tiles)
eq(n,0) :s(return)
take = order(substr(g.tiles,1,n))
g.tiles = substr(g.tiles, n + 1) :(return)
take.end
define('traceoff()') :(traceoff.end)
* Initiate tracing.
traceoff
&ftrace = &trace =
g.scoring = g.tracing = 0
out('stop TRACING ')
traceoff.end
define('traceon()') :(traceon.end)
* Initiate tracing.
traceon
out('start TRACING')
* &ftrace = &trace = 1500000
g.scoring = g.tracing = 1
:(return)
traceon.end
define('turn(pid,mode)i,n,manual,state,points.player,'
. 'points.fribble') :(turn.end)
* Play a turn in a game.
* Steps are
* 1. Replenish tiles before making move if managing tiles by hand.
* 2. Find or enter the move to be played.
* 3. Make the move by updating the data structures, scores, etc.
* 4. If not managing tiles by hand, use fribble to update the rack.
turn
player = g.players[pid]
rack(player) = eq(kind(player),player.kind.move) getrack()
ne(f.trace) out('enter turn pid=' pid ' ' show.player(pid))
eq(g.trace,g.turn) traceon()
* Replenish tiles before making the move.
* This is needed when playing in team mode.
* need to enter your tiles from the wwf board.
eq(f.mode,f.mode.move) :s(turn.move)
eq(f.mode,f.mode.auto) :s(turn.auto)
ne(kind(player),player.kind.team) :s(turn.pickmove)
rack(player) = replenish(pid)
ne(f.trace) out('rack pid=' pid ' now ' rack(player))
ne(f.trace) out(show.player(pid))
:(turn.pickmove)
turn.move
* Here to read in tiles and state of board.
* rack(player) = getrack() :f(turn.move.err)
out('Move tiles are ',rack(player))
getlines()
* :(end)
g.move = find(pid,g.turn) :s(turn.move.ok)
out('turn.move find failed') :(end)
turn.move.ok
:(turn.make)
turn.pickmove
log( 'rack ' pid ' "' rack(player) '"')
* 2. Find or enter the move to be played.
* Here to pick the next move.
* You need to enter the foe's move when playing as a team,
* and your own move when playing a solo game.
eq(f.mode,f.mode.auto) :s(turn.auto)
eq(kind(player),player.kind.foe) :s(turn.manual)
* Enable next line to get 'enhanced' mode where Fribble reports
* move it would have made
* eq(kind(player),player.kind.solo) :s(turn.solo)
eq(kind(player),player.kind.solo) :s(turn.manual)
turn.auto
* Here to have fribble find the best move.
ne(f.trace) out('fribble making move.')
* ne(kind(player),player.kind.auto) out('computing move ...')
g.move = find(pid,g.turn) :f(turn.fail)
* ne(f.trace) out('auto move ' show.move(g.move))
* ne(kind(player),player.kind.auto) out('... computed')
:(turn.make)
turn.manual
* Here to enter the move manually
out('TURN.MANUAL')
ne(f.trace) out('getting move manually')
manual = move.input()
ident(datatype(manual),'move') :f(turn.manual.nomove)
g.move = manual :(turn.validate)
turn.manual.nomove
* Here if manual didn't return a move, so branch
* to the corresponding handler.
manual 'error' :s(turn.manual.error)
:($('turn.' move))
turn.solo
* Here to when playing solo. Get the player's move, then
* find what fribble would have played, and show the difference.
turn.solo.in
ne(f.trace) out('getting move manually')
manual = move.input()
ident(datatype(manual),'move') :f(turn.solo.nomove)
out('solo player move ' show.move(manual))
g.move = manual :(turn.solo.fribble.havemove)
turn.solo.nomove
* Here if manual didn't return a move, so branch
* to the corresponding handler.
manual 'error' :s(turn.manual.error)
target = $('turn.' manual)
out('solo no move target datatype ' datatype(target) ' ' target)
out('turn.solo.nomove ' manual)
:($('turn.' manual))
turn.solo.move
eq(g.turn,1) valid.start(manual) :s(turn.solo.fribble.havemove)
ne(g.turn,1) valid(manual) :s(turn.solo.fribble.havemove)
out('invalid move - try again') :(turn.solo.in)
turn.solo.fribble.havemove
g.move = manual
* G.move is the player's valid move.
* Save the state, find the move fribble would have made,
* and report the results to the player.
state = state.save()
move = find(pid, rack) :s(turn.solo.fribble.move)
* Here if fribble couldn't find a valid move.
out('Hmmm ... Fribble unable to find a valid move.'):(turn.validate)