-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprogram.lsp
2635 lines (2506 loc) · 126 KB
/
program.lsp
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
;; ************************************************************
;; * Name: Philip Glazman *
;; * Project: Kono - Lisp Implementation *
;; * Class: CMPS 366 Organization of Programming Languages *
;; * Date: 2/6/2018 *
;; ************************************************************
;; TO RUN: sbcl --non-interactive --load program.lsp
;; /* *********************************************
;; Source Code for game logic and utility functions.
;; ********************************************* */
;; /* *********************************************************************
;; Function Name: randomDice
;; Purpose: Returns a number between 2 and 12. Simluates dice roll.
;; Parameters:
;; none.
;; Return Value: A number between 2 and 12.
;; Local Variables:
;; randomSeed, stores random state needed to seed randomness.
;; Algorithm:
;; 1) Seed randomness.
;; 2) Use random function to generate random number.
;; Assistance Received: none
;; ********************************************************************* */
(defun randomDice ()
(let* ( (randomSeed (make-random-state t)))
(+ 2 (random 11 randomSeed))))
;; /* *********************************************************************
;; Function Name: choosefirstPlayer
;; Purpose: Returns the first player in a list. Will either be (HUMAN) or (COMPUTER).
;; Parameters:
;; none.
;; Return Value: List containing (HUMAN) or list containing (COMPUTER). List will contain first player to play game.
;; Local Variables:
;; humanDice, holds atom from randomDice function. Represents dice roll for human.
;; computerDice, holds atom from randomDice function. Represents dice roll for computer.
;; Algorithm:
;; 1) Get random dice roll for human.
;; 2) Get random dice roll for computer.
;; 3) Output dice rolls to human.
;; 4) If human dice roll is greater than computer dice roll, then return list (HUMAN).
;; 5) If human dice roll is less than computer dice roll, then return list (COMPUTER).
;; 6) Else if the dice rolls are equal, then recursive call function.
;; Assistance Received: none
;; ********************************************************************* */
(defun choosefirstPlayer()
(let* ( (humanDice (randomDice))
(computerDice (randomDice)) )
(format t "Human rolls ~D. ~%" humanDice)
(format t "Computer rolls ~D. ~%" computerDice)
(cond ( (> humanDice ComputerDice)
(list 'human) )
( (< humanDice ComputerDice)
(list 'computer) )
( (= humanDice ComputerDice)
(choosefirstPlayer)))))
;; /* *********************************************************************
;; Function Name: computerColor
;; Purpose: Returns list holding computer player's color.
;; Parameters:
;; none.
;; Return Value: List holding computer player's color, and human player's color.
;; Local Variables:
;; randomColor, holds atom from random function. This is a random 0 or 1 that chooses the computer player's color.
;; randomSeed, stores random state needed to seed randomness.
;; Algorithm:
;; 1) Get random 0 or 1.
;; 2) If number is 1, then computer is white.
;; 3) Else if number is 0, then computer is black.
;; Assistance Received: none
;; ********************************************************************* */
(defun computerColor ()
(let* ( (randomSeed (make-random-state t))
(randomColor (random 1 randomSeed)))
(cond ( (= randomColor 1)
(append (append (list 'w) (list 'human)) (list 'b)) )
( (= randomColor 0)
(append (append (list 'b) (list 'human)) (list 'w))))))
;; /* *********************************************************************
;; Function Name: chooseColor
;; Purpose: Depending on who the first player is, ask first player for their color.
;; Parameters:
;; none.
;; Return Value: List holding first player and the first player's color choice.
;; Local Variables:
;; none.
;; Algorithm:
;; 1) If first player is human, then ask human for what color they will play.
;; 2) If first palyer ic omputer, randomly choose color for computer using computerColor function.
;; Assistance Received: none
;; ********************************************************************* */
(defun chooseColor(firstPlayer)
(cond ( (string= (first firstPlayer) 'human)
(append firstPlayer (readHumanColor)) )
( (string= (first firstPlayer) 'computer)
(append firstPlayer (computerColor )))))
;; /* *********************************************************************
;; Function Name: getPlayerColor
;; Purpose: Returns the color of the player.
;; Parameters:
;; players, list holding each player and its player color
;; currentTurn, atom holding player to get color of.
;; Return Value: Atom that is either W or B for player color.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the player is the third in the players list, return the fourth item in the players list.
;; 2) If the player is the first in the players list, return the second item in the players list.
;; Assistance Received: none
;; ********************************************************************* */
(defun getPlayerColor (players currentTurn)
(cond ( (string= currentTurn (first (rest (rest players))) )
(first (rest (rest (rest players)))))
( (string= currentTurn (first players))
(first (rest players)))))
;; /* *********************************************************************
;; Function Name: getOppositePlayerColor
;; Purpose: Returns the color of the opposite player.
;; Parameters:
;; playerColor, color of the player that you want the opposite of.
;; Return Value: Atom that is either W or B for player color.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If player color is white, return black.
;; 2) If player color is black, return white.
;; Assistance Received: none
;; ********************************************************************* */
(defun getOppositePlayerColor (playerColor)
(cond ( (string= playerColor 'w)
'b)
( (string= playerColor 'b)
'w)))
;; /* *********************************************************************
;; Function Name: getSuperPieceForPlayerColor
;; Purpose: Returns the super piece of a given player color. Returns lower-case letter of player color.
;; Parameters:
;; playerColor, color of the player.
;; Return Value: String holding either "w" or "b" as super piece.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If player color is white, return lower-case white string.
;; 2) If player color is black, return lower-case black string.
;; Assistance Received: none
;; ********************************************************************* */
(defun getSuperPieceForPlayerColor (playerColor)
(cond ( (string= playerColor "W")
"w")
( (string= playerColor "B")
"b")))
;; /* *********************************************************************
;; Function Name: getNextPlayer
;; Purpose: Return the next player that will be playing.
;; Parameters:
;; currentTurn, holds who is current player.
;; Return Value: Name of the player that is next.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If current player is human, return computer.
;; 2) If current player is computer, return human.
;; Assistance Received: none
;; ********************************************************************* */
(defun getNextPlayer (currentTurn)
(cond ( (string= currentTurn 'human )
'computer)
( (string= currentTurn 'computer)
'human)))
;; /* *********************************************************************
;; Function Name: getOpponentColor
;; Purpose: Return the color of the opponent.
;; Parameters:
;; players, list holding each player and its color.
;; currentTurn, holds who is current player.
;; Return Value: The color of the opponent player.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the current player is second in the players list, return the color of the first player.
;; 2) If the current player is first in the players list, return the color of the second player.
;; Assistance Received: none
;; ********************************************************************* */
(defun getOpponentColor (players currentTurn)
(cond ( (string= currentTurn (first (rest (rest players))) )
(first (rest players)))
( (string= currentTurn (first players))
(first (rest (rest (rest players)))))))
;; /* *********************************************************************
;; Function Name: flatten
;; Purpose: Remove nested lists in the provided list and concatenates the lists.
;; Parameters:
;; list, the list to unnest.
;; Return Value: A new list that unnested lists inside.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the list is empty, return empty list.
;; 2) If the first item of the list is an atom, prepend it to the rest of the list.
;; 3) Default option is to recursively call function while appending the first of the list to the rest of the list.
;; Assistance Received: Recieved help from stackoverflow.
;; https://stackoverflow.com/questions/2680864/how-to-remove-nested-parentheses-in-lisp
;; ********************************************************************* */
(defun flatten (list)
(cond ;; If list is empty, return empty list.
( (eq list nil)
())
;; If the first in the list is an atom, add it to the rest of the list.
( (atom (first list))
(cons (first list) (flatten (rest list))))
;; Recursively call function.
(t
(append (flatten (first list)) (flatten (rest list))))))
;; /* *********************************************************************
;; Function Name: getCountofBlack
;; Purpose: Get the number of remaining black pieces left on the board.
;; Parameters:
;; board, unnested board list.
;; count, the number of black pieces.
;; Return Value: The count of the number of black pieces left on the board.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Recursively call getCountofBlack until there is no more board left.
;; 2) Check if the first of the board is black, if it is, increment count and call getCountOfBlack with the rest of board.
;; 3) Else, Call getCountOfBlack with the rest of board.
;; 4) TODO: recursively call function without count parameter.
;; Assistance Received: None.
;; ********************************************************************* */
(defun getCountofBlack (board count)
(cond ( (eq (first board) nil)
count)
( (OR (string= (first board) "B") (string= (first board) "b"))
(getCountOfBlack (rest board) (+ count 1)))
(t
(getCountOfBlack (rest board) count))))
;; /* *********************************************************************
;; Function Name: getCountofWhite
;; Purpose: Get the number of remaining white pieces left on the board.
;; Parameters:
;; board, unnested board list.
;; count, the number of white pieces.
;; Return Value: The count of the number of white pieces left on the board.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Recursively call getCountofWhite until there is no more board left.
;; 2) Check if the first of the board is white, if it is, increment count and call getCountofWhite with the rest of board.
;; 3) Else, Call getCountofWhite with the rest of board.
;; 4) TODO: recursively call function without count parameter.
;; Assistance Received: None.
;; ********************************************************************* */
(defun getCountofWhite (board count)
(cond ( (eq (first board) nil)
count)
( (OR (string= (first board) "W") (string= (first board) "w"))
(getCountofWhite (rest board) (+ count 1)))
(t
(getCountofWhite (rest board) count))))
;; /* *********************************************************************
;; Function Name: getWhiteSide
;; Purpose: Gets the number of remaining black pieces that have yet to capture the white side.
;; Parameters:
;; board, unnested board list.
;; boardlength, the length of the board.
;; numBlack, the number of black pieces that have not captured the white side.
;; index, index number used for looping through unnested board.
;; Return Value: The count of black pieces that have not captured the white side.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the board is empty, return the number of black pieces left outside of white side.
;; 2) If the home piece has a black piece on it, then decrement the number of black pieces.
;; 3) Recursively call this function until the entire white home side has been accounted for.
;; Assistance Received: None.
;; ********************************************************************* */
(defun getWhiteSide (board boardlength numBlack index)
(cond ( (eq (first board) nil)
numBlack)
;; Checking columns in row one for black piece.
( (AND (<= index (+ boardlength 1)) (OR (string= (first board) "B") (string= (first board) "b")))
(getWhiteSide (rest board) boardlength (- numBlack 1) (+ index 1)))
;; Checking columns in row two for black piece.
( (AND (= index (* boardlength 2)) (OR (string= (first board) "B") (string= (first board) "b")))
(getWhiteSide (rest board) boardlength (- numBlack 1) (+ index 1)))
(t
(getWhiteSide (rest board) boardlength numBlack (+ index 1)))))
;; /* *********************************************************************
;; Function Name: getBlackSide
;; Purpose: Gets the number of remaining white pieces that have yet to capture the black side.
;; Parameters:
;; board, unnested board list.
;; boardlength, the length of the board.
;; numWhite, the number of white pieces that have not captured the white side.
;; index, index number used for looping through unnested board.
;; Return Value: The count of white pieces that have not captured the black side.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the board is empty, return the number of white pieces left outside of black side.
;; 2) If the home piece has a white piece on it, then decrement the number of white pieces.
;; 3) Recursively call this function until the entire black home side has been accounted for.
;; Assistance Received: None.
;; ********************************************************************* */
(defun getBlackSide (board boardlength numWhite index)
(cond ( (eq (first board) nil)
numWhite)
;; Check last row for white pieces.
( (AND (>= index (* boardlength (- boardlength 1))) (OR (string= (first board) "W") (string= (first board) "w")))
(getBlackSide (rest board) boardlength (- numWhite 1) (+ index 1)))
;; Check second to last row for white pieces.
( (AND (= index (* boardlength (- boardlength 2))) (OR (string= (first board) "W") (string= (first board) "w")))
(getBlackSide (rest board) boardlength (- numWhite 1) (+ index 1)))
( (AND (= index (+ (* boardlength (- boardlength 2)) 1)) (OR (string= (first board) "W") (string= (first board) "w")))
(getBlackSide (rest board) boardlength (- numWhite 1) (+ index 1)))
(t
(getBlackSide (rest board) boardlength numWhite (+ index 1)))))
;; /* *********************************************************************
;; Function Name: checkwinner
;; Purpose: Returns t if a winning condition has been met, else returns empty list.
;; Parameters:
;; board, game board.
;; Return Value: T or nil if game condition has been met.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Check if the white side has been captured by black pieces.
;; 2) Check if the black side has been captured by white pieces.
;; Assistance Received: None.
;; ********************************************************************* */
(defun checkwinner(board)
(cond ( (= (getWhiteSide (flatten board) (length board) (getCountofBlack (flatten board) 0) 1) 0)
t)
( (= (getBlackSide (flatten board) (length board) (getCountofWhite (flatten board) 0) 1) 0)
t)
(t
())))
;; /* *********************************************************************
;; Function Name: countBlackScore
;; Purpose: Counts the score for the black player.
;; Parameters:
;; board, unnested game board.
;; boardlength, length of the board.
;; score, current score
;; index, used to traverse board.
;; Return Value: Score which is sum of the total points captured.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Using an unnested game board piece. Check if the index has a black piece on it.
;; 2) Depending on the index, add points to the score.
;; Assistance Received: None.
;; ********************************************************************* */
(defun countBlackScore (board boardlength score index)
(cond ((eq (first board) nil)
score)
((AND (= index 1) (OR (string= (first board) "B") (string= (first board) "b")))
(countBlackScore (rest board) boardlength (+ score 3) (+ index 1)))
((AND (= index 2) (OR (string= (first board) "B") (string= (first board) "b")))
(countBlackScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (= index 3) (OR (string= (first board) "B") (string= (first board) "b")))
(countBlackScore (rest board) boardlength (+ score 5) (+ index 1)))
;; board size is 5
((AND (AND (= index 4) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 5))
(countBlackScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (AND (= index 5) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 5))
(countBlackScore (rest board) boardlength (+ score 3) (+ index 1)))
;; board size is 7
((AND (AND (= index 4) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 7))
(countBlackScore (rest board) boardlength (+ score 7) (+ index 1)))
((AND (AND (= index 5) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 7))
(countBlackScore (rest board) boardlength (+ score 5) (+ index 1)))
((AND (AND (= index 6) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 7))
(countBlackScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (AND (= index 7) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 7))
(countBlackScore (rest board) boardlength (+ score 3) (+ index 1)))
;; board size is 9
((AND (AND (= index 4) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 9))
(countBlackScore (rest board) boardlength (+ score 7) (+ index 1)))
((AND (AND (= index 5) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 9))
(countBlackScore (rest board) boardlength (+ score 9) (+ index 1)))
((AND (AND (= index 6) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 9))
(countBlackScore (rest board) boardlength (+ score 7) (+ index 1)))
((AND (AND (= index 7) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 9))
(countBlackScore (rest board) boardlength (+ score 5) (+ index 1)))
((AND (AND (= index 8) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 9))
(countBlackScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (AND (= index 9) (OR (string= (first board) "B") (string= (first board) "b"))) (= boardlength 9))
(countBlackScore (rest board) boardlength (+ score 3) (+ index 1)))
;; row 2
((AND (= index (+ boardlength 1)) (OR (string= (first board) "B") (string= (first board) "b")))
(countBlackScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (= index (* boardlength 2)) (OR (string= (first board) "B") (string= (first board) "b")))
(countBlackScore (rest board) boardlength (+ score 1) (+ index 1)))
(t
(countBlackScore (rest board) boardlength score (+ index 1)))))
;; /* *********************************************************************
;; Function Name: countWhiteScore
;; Purpose: Counts the score for the white player.
;; Parameters:
;; board, unnested game board.
;; boardlength, length of the board.
;; score, current score
;; index, used to traverse board.
;; Return Value: Score which is sum of the total points captured.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Using an unnested game board piece. Check if the index has a white piece on it.
;; 2) Depending on the index, add points to the score.
;; Assistance Received: None.
;; ********************************************************************* */
(defun countWhiteScore (board boardlength score index)
(cond ((eq (first board) nil)
score)
((AND (= index (+ (* boardlength (- boardlength 1)) 1)) (OR (string= (first board) "W") (string= (first board) "w")))
(countWhiteScore (rest board) boardlength (+ score 3) (+ index 1)))
((AND (= index (+ (* boardlength (- boardlength 1)) 2)) (OR (string= (first board) "W") (string= (first board) "w")))
(countWhiteScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (= index (+ (* boardlength (- boardlength 1)) 3)) (OR (string= (first board) "W") (string= (first board) "w")))
(countWhiteScore (rest board) boardlength (+ score 5) (+ index 1)))
;; board size is 5
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 4)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 5))
(countWhiteScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 5)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 5))
(countWhiteScore (rest board) boardlength (+ score 3) (+ index 1)))
;; board size is 7
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 4)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 7))
(countWhiteScore (rest board) boardlength (+ score 7) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 5)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 7))
(countWhiteScore (rest board) boardlength (+ score 5) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 6)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 7))
(countWhiteScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 7)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 7))
(countWhiteScore (rest board) boardlength (+ score 3) (+ index 1)))
;; board size is 9
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 4)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 9))
(countWhiteScore (rest board) boardlength (+ score 7) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 5)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 9))
(countWhiteScore (rest board) boardlength (+ score 9) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 6)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 9))
(countWhiteScore (rest board) boardlength (+ score 7) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 7)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 9))
(countWhiteScore (rest board) boardlength (+ score 5) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 8)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 9))
(countWhiteScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (AND (= index (+ (* boardlength (- boardlength 1)) 9)) (OR (string= (first board) "W") (string= (first board) "w"))) (= boardlength 9))
(countWhiteScore (rest board) boardlength (+ score 3) (+ index 1)))
;; row 2
((AND (= index (* boardlength (- boardlength 1))) (OR (string= (first board) "W") (string= (first board) "w")))
(countWhiteScore (rest board) boardlength (+ score 1) (+ index 1)))
((AND (= index (+ (* boardlength (- boardlength 2)) 1)) (OR (string= (first board) "W") (string= (first board) "w")))
(countWhiteScore (rest board) boardlength (+ score 1) (+ index 1)))
(t
(countWhiteScore (rest board) boardlength score (+ index 1)))))
;; /* *********************************************************************
;; Function Name: calculateScores
;; Purpose: Calculates scores for computer and human players.
;; Parameters:
;; board, game board.
;; boardlength, length of the board.
;; Return Value: Returns list containing score for white and black players.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Get scores for white player.
;; 2) Get scores for black player.
;; 3) Put scores into list and return the list.
;; Assistance Received: None.
;; ********************************************************************* */
(defun calculateScores (board boardlength)
;; Return white score and black score in that order.
(list (+ (countWhiteScore board boardlength 0 1) (* (- (+ boardlength 2) (getCountOfBlack board 0)) 5))
(+ (countBlackScore board boardlength 0 1) (* (- (+ boardlength 2) (getCountofWhite board 0)) 5))))
;; /* *********************************************************************
;; Function Name: announceScores
;; Purpose: Outputs player score.
;; Parameters:
;; player, player name - either computer or human.
;; score, player's score.
;; Return Value: None.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Output player and score.
;; Assistance Received: None.
;; ********************************************************************* */
(defun announceScores (player score)
(format t "~A scored ~S points. ~%" player score))
;; /* *********************************************************************
;; Function Name: calculateWinner
;; Purpose: Calculates the winner for the current game round.
;; Parameters:
;; playerOne, first player.
;; scoreOne, player one's score.
;; playerTwo, second player.
;; scoreTwo, player two's score.
;; Return Value: List containing winner and difference of scores to be awarded.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Check if scoreOne is greater than scoreTwo. If so, then output that the playerOne is winner.
;; 2) Check if scoreOne is less than scoreTwo. If so, then output that the playerTwo is winner.
;; 3) If it is a tie, output that it is a tie.
;; Assistance Received: None.
;; ********************************************************************* */
(defun calculateWinner (playerOne scoreOne playerTwo scoreTwo)
(cond ( (> scoreOne scoreTwo)
(format t "~A won and is awarded ~S points ~%" playerOne (- scoreOne scoreTwo))
(list playerOne (- scoreOne scoreTwo)))
( (< scoreOne scoreTwo)
(format t "~A won and is awarded ~S points ~%" playerTwo (- scoreTwo scoreOne))
(list playerTwo (- scoreTwo scoreOne)))
( (= scoreOne scoreTwo)
(format t "There is no clear winner. It is a draw. ~%")
(list playerOne 0))))
;; /* *********************************************************************
;; Function Name: getWinner
;; Purpose: Announces scores for the current round and calls function to calculate Winner.
;; Parameters:
;; board, game board.
;; players, players list holding players and player colors.
;; Return Value: List containing winner and difference of scores to be awarded.
;; Local Variables:
;; scores, list that has total points for each player for the round.
;; Algorithm:
;; 1) Announce first player's points.
;; 2) Announce second player's points.
;; 3) Announce winner.
;; Assistance Received: None.
;; ********************************************************************* */
(defun getWinner(board players)
;; scores for the game.
(let* ( (scores (calculateScores (flatten board) (length board))))
;; if first player is white, announce the white score
(cond ( (string= (first (rest players)) "W")
(announceScores (first players) (first scores))
(announceScores (first (rest (rest players))) (first (rest scores)))
(calculateWinner (first players) (first scores) (first (rest (rest players))) (first (rest scores))))
;; if first player is black, announce the black score
( (string= (first (rest players)) "B")
(announceScores (first players) (first (rest scores)))
(announceScores (first (rest (rest players))) (first scores))
(calculateWinner (first players) (first (rest scores)) (first (rest (rest players))) (first scores))))))
;; /* *********************************************************************
;; Function Name: announceTournamentScores
;; Purpose: Announces tournament scores.
;; Parameters:
;; player, player to be announced.
;; score, player's score.
;; Return Value: None.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Announce player's tournament score.
;; Assistance Received: None.
;; ********************************************************************* */
(defun announceTournamentScores (player score)
(format t "~A has ~S points. ~%" player score))
;; /* *********************************************************************
;; Function Name: tournamentControl
;; Purpose: Main tournament control logc. Calls functions to announce scores and asks user to play again.
;; Parameters:
;; prevWinner, previous winner of the tournament.
;; scores, scores list that has tournament score for each player.
;; Return Value: None.
;; Local Variables:
;; tournamentScore, list hold tournament scores for each player.
;; playAgain, choice for human to play round again.
;; Algorithm:
;; 1) Announce player's tournament score.
;; 2) Ask human if they want to play again. Record answer to local variable.
;; 3) Previous winner plays first.
;; Assistance Received: None.
;; ********************************************************************* */
(defun tournamentControl (prevWinner scores)
;; Get tournament scores.
(let* ( (tournamentScore (calculateTournamentScore prevWinner scores)))
;; Announce tournament scores.
(format t "Tournament Scores: ~%")
(announceTournamentScores (first tournamentScore) (first (rest tournamentScore)))
(announceTournamentScores (first (rest (rest tournamentScore))) (first (rest (rest (rest tournamentScore)))))
;; Ask user to play again.
(let* ( (playAgain (readPlayAgain)))
(cond ( (string= playAgain "Y")
;; Previous winner plays first.
(newRound tournamentScore (first prevWinner)))
( (string= playAgain "N")
;; Quit game.
(Quit))))))
;; /* *********************************************************************
;; Function Name: calculateTournamentScore
;; Purpose: Calculates tournament score by adding round score to the tournament score.
;; Parameters:
;; roundScores, round scores.
;; tournamentScores, tournament scores.
;; Return Value: Returns new scores list containing the awarded difference in points to the tournament scores.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If first player is computer, return new list object given that the first player is computer.
;; 2) If first player is human, return new list object given that the first player is human.
;; 3) I unfortunately did not standardize the scores list, therefore I have to always check to see who the first player is and adjust accordingly.
;; Assistance Received: None.
;; ********************************************************************* */
(defun calculateTournamentScore (roundScores tournamentScores)
(cond ( (string= (first roundScores) "COMPUTER")
(list 'computer (+ (first (rest tournamentScores)) (first (rest roundScores))) 'human (first (rest (rest (rest tournamentScores)))) (+ 1 (first (rest (rest (rest (rest tournamentScores))))))))
( (string= (first roundScores) "HUMAN")
(list 'computer (first (rest tournamentScores)) 'human (+ (first (rest (rest (rest tournamentScores)))) (first (rest roundScores))) (+ 1 (first (rest (rest (rest (rest tournamentScores))))))))))
;; /* *********************************************************************
;; Function Name: playHuman
;; Purpose: Logic for human player.
;; Parameters:
;; players, list of players.
;; board, game board.
;; scores, current tournament scores.
;; playerColor, human player color.
;; Return Value: None.
;; Local Variables:
;; coordinates, row and column positions of human player piece.
;; Algorithm:
;; 1) Ask for player coordinates.
;; 2) Ask for direction to move.
;; 4) Validate coordinates and final coordinates.
;; 5) Update board if valid, else ask again.
;; Assistance Received: None.
;; ********************************************************************* */
(defun playHuman (players board scores playerColor)
(let*( (coordinates (append (readHumanRow) (readHumanColumn) ))
;; get final coordinates
(finalCoordinates (readHumanDirection coordinates))
;; checks if the piece at coordinates is equal to the player color
(isValidPiece (validPieceToMove board coordinates))
;; checks if the piece at new coordinates is "+"
(isValidDirection (validDirectionToMove board finalCoordinates)))
(cond ( (AND (OR (string= isValidPiece playerColor) (string= isValidPiece (getSuperPieceForPlayerColor playerColor))) (OR (string= isValidDirection (getSuperPieceForPlayerColor (getOppositePlayerColor playerColor))) (OR (string= isValidDirection "+") (string= isValidDirection (getOppositePlayerColor playerColor)))))
(playRound players (updateBoard board coordinates finalCoordinates (list isValidPiece)) 'computer scores))
(t
(princ "Not a valid move. Try again.")
(playRound players board 'human scores)))))
;; /* *********************************************************************
;; Function Name: rev
;; Purpose: Reverses a list.
;; Parameters:
;; list, a list to reverse.
;; Return Value: None.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If list is null, return empty list.
;; 2) Recursively append the rest of the list to the first of the list.
;; Assistance Received: Recieved help on stackoverflow.
;; https://stackoverflow.com/questions/34422711/reversing-list-in-lisp
;; ********************************************************************* */
(defun rev (list)
(cond ( (null list)
())
(t
(append (rev (rest list)) (list (first list))))))
;; /* *********************************************
;; Source Code for board model and display.
;; ********************************************* */
;; /* *********************************************************************
;; Function Name: makeRowForBoard
;; Purpose: Generates the row for the board.
;; Parameters:
;; column, the column index.
;; row, the row index.
;; boardSize, board size.
;; Return Value: List containing the pieces for that row.
;; Local Variables:
;; none.
;; Algorithm:
;; 1) Recusive function where base case is when column index is 0.
;; 2) Continue to loop through the function passing each row until column index is 0.
;; 4) If row index is one, populate the entire row with "W" pieces.
;; 5) If row is second, given certain columns , place a "W" piece.
;; 6) If row is last row, populate entire row with "B" pieces.
;; 7) If row is second to last, given certain columns, place a "B" piece.
;; Assistance Received: none
;; ********************************************************************* */
(defun makeRowForBoard (column row boardSize)
(cond ( (= column 0)
() )
;; First row is white.
( (= row 1)
(append (list "W")
(makeRowForBoard (- column 1) row boardSize)) )
;; Place white pieces on second row.
( (and (= row 2) (OR (= column 1) (= column boardSize)))
(append (list "W")
(makeRowForBoard (- column 1) row boardSize)) )
;; Place black pieces on last row
( (= row boardSize)
(append (list "B")
(makeRowForBoard (- column 1) row boardSize)) )
;; Place black pieces on second to last row
( (and (= row (- boardSize 1)) (OR (= column 1) (= column boardSize)))
(append (list "B")
(makeRowForBoard (- column 1) row boardSize)) )
;; Place regular + pieces
(t
(append (list "+")
(makeRowForBoard (- column 1) row boardSize)))))
;; /* *********************************************************************
;; Function Name: makeBoard
;; Purpose: Generates board with size.
;; Parameters:
;; boardSize, the board size.
;; constSize, actual board size.
;; Return Value: List of lists that represents board.
;; Local Variables:
;; none.
;; Algorithm:
;; 1) Populate each row of the board and append it to the board list.
;; 2) While board size is not zero, append makeBoard function output to the board.
;; 4) Decrement board size while appending output to board.
;; Assistance Received: none
;; ********************************************************************* */
(defun makeBoard (boardSize constSize)
(cond ( (= boardSize 0)
() )
(t
(append (makeBoard (- boardSize 1) constSize)
(list (makeRowForBoard constSize boardSize constSize))))))
;; /* *********************************************************************
;; Function Name: displayBoard
;; Purpose: Prints board with coordinate grid to standard output.
;; Parameters:
;; board, board object.
;; boardindex, initialized at 0. Increments with each pass.
;; boardlength, constant length of the board.
;; Return Value: Board to standard output.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Recursive function that loops through each row in board and prints it.
;; 2) If there is no more row, print South and West compasses.
;; 3) If the board index is zero, print the North compass. And increment board index.
;; 4) Print the row and row number. Increment the board index.
;; 5) Using tail recursion, print the column numbers.
;; 6) Using tail recursion, if there are no more column numbers, print the East compass.
;; Assistance Received: none
;; ********************************************************************* */
(defun displayBoard (board boardindex boardlength)
(cond
;; If there is no more board left, print compasses South and West.
( (= (length board) 0)
(format t "~A ~%" "S")
(format t "~A " "W"))
;; If the the board is starting to print (boardindex = 0), then print North compass.
( (= boardindex 0)
(format t "~D ~%" 'N)
;; Call displayBoard.
(displayBoard board (+ boardindex 1) boardlength) )
;; Print the row for the board, row #.
(t
(format t "~D ~A ~%" boardindex (first board))
(displayBoard (rest board) (+ boardindex 1) boardlength)
;; Print column #.
(format t "~D " (length board))
;; If there are no more columns left, print East compass.
(cond ( (= (length board) boardlength)
(format t "~D ~%" 'E))))))
;; /* *********************************************************************
;; Function Name: filterRows
;; Purpose: Returns a list containing a row from the board given the row number.
;; Parameters:
;; board, board object.
;; boardlength, constant length of the board.
;; row, the row number of the row to return.
;; Return Value: List of the board at the given row number.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the length of the board is equal to the row number, return the row.
;; 2) Else call function and decrement one row list from the board.
;; Assistance Received: none
;; ********************************************************************* */
(defun filterRows (board boardlength row)
(cond ( (= (length board) (- boardlength row) )
(first board) )
(t
(filterRows (rest board) boardlength row))))
;; /* *********************************************************************
;; Function Name: filterColumns
;; Purpose: Returns a list containing a column from the board given the column number.
;; Parameters:
;; row, row list.
;; boardlength, constant length of the board.
;; column, the column number of the row to return.
;; Return Value: List of the column at column number.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the length of the row is equal to the column number, return the column.
;; 2) Else call function and decrement one column list from the row.
;; Assistance Received: none
;; ********************************************************************* */
(defun filterColumns (row boardlength column)
(cond ( (= (length row) (- boardlength column) )
(first row))
(t (filterColumns (rest row) boardlength column))))
;; /* *********************************************************************
;; Function Name: validPieceToMove
;; Purpose: Checks if a given piece at coordinates can be moved. Returns piece color at coordinates. Validation is done at function that calls.
;; Parameters:
;; board, board object.
;; coordinates, list containing row and column of piece.
;; Return Value: Returns the piece at coordinates.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Check if the row or column is less than zero. IF it is, return a X signalling that it is not a valid piece to move.
;; 2) Check if the row or column is greater than the length of the board. IF it is, return a X signalling that it is not a valid piece to move.
;; 3) Filter the columns and rows to return the piece located at that coordinate.
;; Assistance Received: none
;; ********************************************************************* */
(defun validPieceToMove (board coordinates)
(cond ;; Check if row or coordinate is less than zero.
( (OR (<= (first coordinates) 0) (<= (first (rest coordinates)) 0))
'x)
;; Check if row or coordinate is greater than legth of board.
( (OR (> (first coordinates) (length board)) (> (first (rest coordinates)) (length board)))
'x)
;; Filter columns and row to return the piece at the provided coordinates.
(t
(filterColumns (filterRows board (+ (length board) 1) (first coordinates)) (+ (length board) 1) (first (rest coordinates))))))
;; /* *********************************************************************
;; Function Name: validDirectionToMove
;; Purpose: Checks if the coordinates provided are a valid place to move by returning the piece located at that coordinate.
;; Parameters:
;; board, board object.
;; finalCoordinates, list containing row and column of place to move to.
;; Return Value: Returns the piece at finalCoordinates in board.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Check if the row or column is less than zero. If it is, return a X signalling that it is not a valid piece to move to.
;; 2) Check if the row or column is greater than the length of the board. IF it is, return a X signalling that it is not a valid piece to move to.
;; 3) Filter the columns and rows to return the piece located at that coordinate.
;; Assistance Received: none
;; ********************************************************************* */
(defun validDirectionToMove (board finalCoordinates)
(cond ;; Check if coordinate is less than zero.
( (OR (<= (first finalCoordinates) 0) (<= (first (rest finalCoordinates)) 0))
'x)
;; Check if coordinate is greater than length of the board.
( (OR (> (first finalCoordinates) (length board)) (> (first (rest finalCoordinates)) (length board)))
'x)
;; Return piece located at the coordinate.
(t
(filterColumns (filterRows board (+ (length board) 1) (first finalCoordinates)) (+ (length board) 1) (first (rest finalCoordinates))))))
;; /* *********************************************************************
;; Function Name: updateColumn
;; Purpose: Updates the piece at a given column index of a row.
;; Parameters:
;; row, row list.
;; boardlength, length of the board.
;; columnIndex, index of piece to update.
;; piece, piece that will replace existing piece at columnIndex.
;; finalCoordinates, list containing row and column of place to move to.
;; Return Value: Returns a row list with the updated piece at the specific column index.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the column index equals the length of the row, append the new peice to the rest of the row.
;; 2) If not, call the function recursively while prepending the first of the row using head recursion.
;; Assistance Received: none
;; ********************************************************************* */
(defun updateColumn (row boardlength columnIndex piece)
(cond ;; Found columnIndex
( (= (length row) (- boardlength columnIndex) )
(append piece (rest row)))
;; Loop through the remaning row. Prepend first of the row using head recursion.
(t
(cons (first row) (updateColumn (rest row) boardlength columnIndex piece)))))
;; /* *********************************************************************
;; Function Name: updateRow
;; Purpose: Updates the piece at a given column index of a row.
;; Parameters:
;; board, board object.
;; boardlength, length of the board.
;; rowIndex, index of row to update.
;; row, row that will replace row and rowIndex.
;; Return Value: Returns the board object with the updated board.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the row index equals the length of the board, append the new row to the rest of the board.
;; 2) If not, call the function recursively while prepending the first of the board using head recursion.
;; Assistance Received: none
;; ********************************************************************* */
(defun updateRow (board boardlength rowIndex row)
(cond ;; Found row at row index. Append row to the rest of the board.
( (= (length board) (- boardlength rowIndex) )
(append row (rest board)))
;; Recursively call the function with the rest of the board. Using head recursion, prepend the first board.
(t
(cons (first board) (updateRow (rest board) boardlength rowIndex row)))))
;; /* *********************************************************************
;; Function Name: updateCoordinates
;; Purpose: Holds logic to update coordinates.
;; Parameters:
;; board, board object.
;; row, row number of piece to update.
;; column, column number of piece to update.
;; piece, piece that will replace existing piece.
;; Return Value: Returns new board with updated piece at coordinates.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Call updateRow.
;; Assistance Received: none
;; ********************************************************************* */
(defun updateCoordinates (board row column piece)
(updateRow board (+ (length board) 1) row (list (updateColumn (filterRows board (+ (length board) 1) row) (+ (length board) 1) column piece))))
;; /* *********************************************************************
;; Function Name: updateBoard
;; Purpose: Holds logic to update board. It will update new coordinate and remove old coordinate.
;; Parameters:
;; board, board object.
;; oldCoordinates, list containing old row and old column of piece.
;; newCoordinates, list containing new row and new column of piece.
;; piece, piece that will replace existing piece.
;; Return Value: Returns new board with updated pieces at coordinates.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) Call updateCoordinates.
;; Assistance Received: none
;; ********************************************************************* */
(defun updateBoard (board oldCoordinates NewCoordinates piece)
;; Update new coordinate and remove old coordinate.
(updateCoordinates (updateCoordinates board (first NewCoordinates) (first (rest NewCoordinates)) (checkSuperPiece (length board) piece newCoordinates)) (first oldCoordinates) (first (rest oldCoordinates)) (list "+")))
;; /* *********************************************************************
;; Function Name: checkSuperPiece
;; Purpose: Checks if the piece at coordinate is eligible to become a super piece.
;; Parameters:
;; boardlength, length of the board.
;; piece, piece to check eligibility for upgrade.
;; coordinate, coordinate of the piece.
;; Return Value: If the piece can be upgraded, returns upgraded super piece. If not, returns regular piece.
;; Local Variables:
;; None.
;; Algorithm:
;; 1) If the piece is white, check if the piece reached the black side of the board. If so, return the super piece of that piece.
;; 2) If the piece is black, check if the piece reached the white side of the board. If so, return the super piece of that piece.
;; 3) If the piece is not eligible to be upgraded to super piece or is already super piece, return the piece.
;; Assistance Received: none
;; ********************************************************************* */
(defun checkSuperPiece(boardlength piece coordinate)
(cond ;; Check if the white piece can be upgraded.
( (AND (string= (first piece) "W") (= (first coordinate) boardlength))
(list (getSuperPieceForPlayerColor (first piece))))
;; Check if the black piece can be upgraded.
( (AND (string= (first piece) "B") (= (first coordinate) 1))
(list (getSuperPieceForPlayerColor (first piece))))
;; Default action to return piece.