-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
3,604 additions
and
18 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
; Tic-Tac-Toe board represented as a list of 9 elements | ||
(: board-state (-> Expression Atom)) ; The board-state is an expression type, stored as an atom. | ||
|
||
; Constants for players and empty cells | ||
(: X cv) (: O cv) (: . cv) ; Defining symbols for 'X', 'O', and empty cell ('.'). | ||
|
||
; Define players | ||
(: X Player) (: O Player) ; 'X' and 'O' are both players. | ||
|
||
; Determine the opponent of the current player | ||
(: opponent (-> Player Player)) ; Returns the opponent of the current player. | ||
(= (opponent X) O) ; X's opponent is O. | ||
(= (opponent O) X) ; O's opponent is X. | ||
|
||
; Initial empty board | ||
!(add-atom &self (board-state (. . . . . . . . .))) ; Initialize the board with empty cells. | ||
|
||
; Function to display the current board | ||
(: display-board (-> board-state Atom)) ; This function takes the board-state and returns an Atom. | ||
(= (display-board) | ||
(match &self (board-state $list) | ||
(println! (format-args "\n | ||
{} | {} | {} \n | ||
--------- \n | ||
{} | {} | {} \n | ||
--------- \n | ||
{} | {} | {} \n | ||
" $list)))) ; Formats the board as a 3x3 grid for display. | ||
|
||
!(println! (format-args "\n | ||
{} | {} | {} \n | ||
--------- \n | ||
{} | {} | {} \n | ||
--------- \n | ||
{} | {} | {} \n | ||
" (1 2 3 4 5 6 7 8 9))) | ||
|
||
; Helper function to get the nth element (1-indexed) | ||
(: nth (-> Int Expression Atom)) ; Retrieves the nth element from the board. | ||
(= (nth 1 $list) (car-atom $list)) ; Base case: when n is 1, return the first element (car-atom). | ||
(= (nth $n $list) | ||
(nth (- $n 1) (cdr-atom $list))) ; Recursion: move to the next element (cdr-atom) and decrease n. | ||
|
||
; Replace nth element in a list (1-indexed) | ||
(: replace-nth (-> Int Atom Expression Expression)) ; Replaces the nth element in a list with a new value. | ||
(= (replace-nth 1 $val $list) | ||
(cons-atom $val (cdr-atom $list))) ; Base case: replace the first element and keep the rest unchanged. | ||
(= (replace-nth $n $val $list) | ||
(cons-atom (car-atom $list) (replace-nth (- $n 1) $val (cdr-atom $list)))) ; Recursive step to replace the nth element. | ||
|
||
; Check for win conditions | ||
(: win-state (-> Expression Player Bool)) ; Checks if a player has won. | ||
; The following patterns match different winning conditions (rows, columns, diagonals). | ||
(= (win-state ($s $s $s $_ $_ $_ $_ $_ $_) $s) True) ; Row 1 | ||
(= (win-state ($_ $_ $_ $s $s $s $_ $_ $_) $s) True) ; Row 2 | ||
(= (win-state ($_ $_ $_ $_ $_ $_ $s $s $s) $s) True) ; Row 3 | ||
(= (win-state ($s $_ $_ $s $_ $_ $s $_ $_) $s) True) ; Column 1 | ||
(= (win-state ($_ $s $_ $_ $s $_ $_ $s $_) $s) True) ; Column 2 | ||
(= (win-state ($_ $_ $s $_ $_ $s $_ $_ $s) $s) True) ; Column 3 | ||
(= (win-state ($s $_ $_ $_ $s $_ $_ $_ $s) $s) True) ; Diagonal 1 | ||
(= (win-state ($_ $_ $s $_ $s $_ $s $_ $_) $s) True) ; Diagonal 2 | ||
|
||
; Check if a player has won | ||
(: check-win (-> board-state Player Bool)) ; Determines if the specified player has a winning condition. | ||
(= (check-win $board $player) | ||
(win-state $board $player)) ; Calls the win-state function to check for winning conditions. | ||
|
||
; Make a move on the board | ||
(: make-move (-> Expression Player Int Expression)) ; Places a player's mark ('X' or 'O') on the board at a specific position. | ||
(= (make-move $board $player $pos) | ||
(replace-nth $pos $player $board)) ; Replaces the nth position with the player's symbol. | ||
|
||
; Game loop for human player | ||
(: game-loop-human (-> Player Atom)) ; Human player�s turn loop. | ||
(= (game-loop-human $human) | ||
(do | ||
((display-board) ; Display the current board. | ||
(println! (format-args "Player {}'s turn." ($human))) ; Print whose turn it is. | ||
(match &self (board-state $board-before)) ; Retrieve the current board-state. | ||
(let $pos (get-player-move) ; Get a valid move from the player. | ||
(and (nth $pos $board-before .) ; Ensure the selected position is empty. | ||
(let $board-after (make-move $board-before $human $pos) ; Update the board with the player's move. | ||
(do ((remove-atom &self (board-state $board-before)) ; Remove the old board-state. | ||
(add-atom &self (board-state $board-after)) ; Add the new board-state. | ||
(if (check-win $board-after $human) ; Check if the player has won. | ||
(println! (format-args "Player {} wins!" ($human))) ; Announce the winner. | ||
(game-loop-computer (opponent $human))))))))))) ; If no win, continue to the computer's turn. | ||
|
||
; Get validated player move (1-9) | ||
(: get-player-move (-> Int)) ; Function to get a move from the player. | ||
(= (get-player-move) | ||
(progn | ||
((println! "Enter position (1-9):") | ||
(flush-output!) | ||
(let $pos (- (get-single-char!) 48) ; Convert the input character to an integer (1-9). | ||
(if (and (>= $pos 1) (<= $pos 9)) ; Ensure the move is within valid range. | ||
$pos ; Return the valid position. | ||
(progn | ||
((println! "Invalid move! Enter position (1-9):") ; Prompt for another input if invalid. | ||
(get-player-move)))))))) | ||
|
||
; Random move for computer | ||
(: random-move (-> board-state Int)) ; Generates a random valid move for the computer. | ||
(= (random-move $board) | ||
(let* (($positions (collapse ; Collapse the list of valid positions. | ||
(let $i (between! 1 9) ; For each position from 1-9, | ||
(if (nth $i $board .) $i))))) ; Check if the position is empty and available. | ||
(if (== $positions ()) -1 ; If no positions are available, return -1. | ||
(random-element! $positions)))) ; Otherwise, return a random valid position. | ||
|
||
; Game loop for the computer player | ||
(: game-loop-computer (-> Player Atom)) ; Computer player's turn loop. | ||
(= (game-loop-computer $computer) ; The computer is $computer | ||
(do | ||
((match &self (board-state $board)) ; Retrieve the current board-state. | ||
(let* (($win-move (find-winning-move $board $computer)) ; Check if the computer has a winning move. | ||
($opponent (opponent $computer)) ; The human player's symbol. | ||
($block-move (find-winning-move $board $opponent)) ; Check if the human can win and block the move. | ||
($random-move (random-move $board))) ; If no win/block, choose a random move. | ||
(let $pos (if (> $win-move 0) $win-move ; Prioritize winning. | ||
(if (> $block-move 0) $block-move ; Then block the opponent's winning move. | ||
$random-move))) ; Otherwise, make a random move. | ||
(if (>= $pos 1) ; If a valid move exists, | ||
(let $board-after (make-move $board $computer $pos) ; Make the move. | ||
(do ((remove-atom &self (board-state $board)) ; Update the board state. | ||
(add-atom &self (board-state $board-after)) | ||
(if (check-win $board-after $computer) ; Check if the computer won. | ||
(println! "Computer wins!") ; Announce the win. | ||
(game-loop-human $opponent)))))))))) ; Otherwise, continue to the human's turn. | ||
|
||
; Start the game | ||
; !(game-loop-human X) ; Start the game with the human player ('X'). | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
; Define the 'select' function to split a list into head and tail. | ||
(= (select $x) | ||
((car-atom $x) (cdr-atom $x))) ; Select decomposes $x into its head and tail. | ||
|
||
; Extended 'select' function with nested let* for more complex deconstruction. | ||
(= (select $x) | ||
(let* (($y (car-atom $x)) ; Extract the head of $x into $y. | ||
($z (cdr-atom $x)) ; Extract the tail of $x into $z. | ||
(($u $v) (select $z))) ; Recursively apply select to $z. | ||
($u (cons-atom $y $v)))) ; Combine $y with the processed tail. | ||
|
||
; Define a function to create a range of numbers from $x to $y. | ||
(= (range $x $y) | ||
(if (== $x $y) ; Base case: if start equals end, return $x. | ||
($x) | ||
(let $z (range (+ $x 1) $y) ; Recursive case: create range for $x+1 to $y. | ||
(cons-atom $x $z)))) ; Add $x to the front of the range list. | ||
|
||
; Main function to solve the N-Queens problem for $n. | ||
(= (nqueens $n) | ||
(let $r (range 1 $n) ; Generate a list of positions 1 to $n. | ||
(nqueens_aux $r ()))) ; Start solving with all positions unplaced. | ||
|
||
; Auxiliary function for solving N-Queens. | ||
(= (nqueens_aux $unplaced $safe) | ||
(if (== $unplaced ()) ; Base case: all queens are placed. | ||
$safe | ||
(let ($q $r) (select $unplaced) ; Split unplaced into current $q and remaining $r. | ||
(if (not_attack $q 1 $safe) ; Check if $q can be placed safely. | ||
(let $safeext (cons-atom $q $safe) ; Extend $safe with the new placement. | ||
(nqueens_aux $r $safeext)))))) ; Recur with remaining queens. | ||
|
||
; Function to check if a queen placement attacks others. | ||
(= (not_attack $q $d $s) | ||
(if (== $s ()) ; Base case: no queens to check against. | ||
True | ||
(let* (($h (car-atom $s)) ; Get the head of the list ($h). | ||
($t (cdr-atom $s))) ; Get the tail of the list ($t). | ||
(if (or (== $q $h) ; Check for same row. | ||
(or (== $q (+ $d $h)) ; Check for diagonal attacks. | ||
(== $h (+ $q $d)))) | ||
False ; Attack detected. | ||
(not_attack $q (+ $d 1) $t))))) ; Recur with the next queen. | ||
|
||
; Call the N-Queens function for a 12x12 chessboard. | ||
|
||
!(range 4 10) |
Oops, something went wrong.