@@ -1,3 +1,8 @@ | |||
# lisp_subdecadence | |||
A Subdecadence generator in Common Lisp | |||
A Subdecadence generator in Common Lisp | |||
I stole the project structure from [Nyx's gema project](https://git.sr.ht/~nyx_land/cl-gema). | |||
I also learned how to make a lisp project from her repo. | |||
Praise Tokhatto. |
@@ -0,0 +1,3 @@ | |||
TODO: highlight pairs/choices | |||
TODO: matrix of associations with lemurs |
@@ -0,0 +1,7 @@ | |||
#!/bin/sh | |||
if command -v cl-launch; then | |||
cl-launch -o subdec -d ! -Q -s subdecadence -r "subd::main" | |||
else | |||
echo "idk what I'm doing" | |||
fi |
@@ -0,0 +1,5 @@ | |||
(in-package #:subdecadence.main) | |||
(defun main () | |||
(let ((g (make-instance 'aeon))) | |||
(play-aeon g))) |
@@ -0,0 +1,21 @@ | |||
(defpackage #:subdecadence.utilities | |||
(:use :cl) | |||
(:export :+base-deck+ :remove-nth :strip-suit | |||
:diff :display-cross :shuffle)) | |||
(defpackage #:subdecadence.core | |||
(:use :cl) | |||
(:export :aeon :play-aeon)) | |||
(defpackage #:subdecadence.main | |||
(:use :cl :subdecadence.core) | |||
(:export :main)) | |||
(defpackage #:subdecadence | |||
(:nicknames :subd) | |||
(:use :cl | |||
:subdecadence.utilities | |||
:subdecadence.core | |||
:subdecadence.main)) | |||
(in-package #:subdecadence) |
@@ -0,0 +1,92 @@ | |||
(in-package #:subdecadence.core) | |||
(defclass aeon () | |||
((deck :accessor deck | |||
:initform (subd::shuffle | |||
(copy-list subd::+base-deck+)) | |||
:type list | |||
:documentation | |||
"The deck of cards.") | |||
(cross-set :accessor cross-set | |||
:initform nil | |||
:type list | |||
:documentation | |||
"The Set-1 cards. They go on the cross.") | |||
(match-set :accessor match-set | |||
:initform nil | |||
:type list | |||
:documentation | |||
"The Set-2 cards. They are dealt face-down.") | |||
(score :accessor score | |||
:initform 0 | |||
:type integer | |||
:documentation | |||
"The score for the current draw.") | |||
(total-score :accessor total-score | |||
:initform 0 | |||
:type integer | |||
:documentation | |||
"The total score for this Aeon.")) | |||
(:documentation "A game of Subdecadence.")) | |||
(defmethod reset-deck ((self aeon)) | |||
"Create a new deck to continue an Aeon." | |||
(setf (deck self) (subd::shuffle | |||
(copy-list subd::+base-deck+)))) | |||
(defmethod draw-sets ((self aeon)) | |||
"Draw 5 cards for cross-set, 5 for match-set, and update deck." | |||
(with-slots (deck cross-set match-set) self | |||
(setf cross-set (subseq deck 0 5)) | |||
(setf match-set (subseq deck 5 10)) | |||
(setf deck (nthcdr 10 deck)))) | |||
(defmethod get-match ((self aeon) &key card) | |||
"Find pairs for a card and calculate score." | |||
(unless (typep card 'fixnum) (error "Card must be a fixnum.")) | |||
(with-slots (score match-set) self | |||
(loop :for match :in match-set | |||
:for index :from 0 | |||
:do (setq match (subd::strip-suit match)) | |||
;; if there's a pair, remove matched card from set to avoid | |||
:when (= (+ card match) 9) ; interfering with later matches | |||
:do (setf match-set (subd::remove-nth match-set index)) | |||
:and :return (setf score ; and add the diff. of pair to score | |||
(+ score (subd::diff card match))) | |||
;; otherwise, subtract card # from score | |||
:finally (setf score (- score card))))) | |||
(defmethod make-matches ((self aeon)) | |||
"Call get-match for every card on the cross." | |||
(with-slots (cross-set match-set) self | |||
(loop :for card :in cross-set | |||
:do (get-match self :card (subd::strip-suit card))))) | |||
(defmethod play-draw ((self aeon)) | |||
"Play a single draw of an Aeon." | |||
(with-slots (cross-set match-set score) self | |||
(draw-sets self) | |||
(subd::display-cross cross-set) | |||
(format t "~A~%~%" match-set) | |||
(make-matches self) | |||
(format t "Score: ~A~%" score))) | |||
(defmethod play-aeon ((self aeon)) | |||
"Play a single Aeon." | |||
(play-draw self) | |||
(with-slots (total-score score deck) self | |||
(unless deck | |||
(reset-deck self)) | |||
(setf total-score (+ total-score score)) | |||
(format t "Total Score: ~A~%" total-score) | |||
(when (> score 0) | |||
(progn | |||
(setf score 0) | |||
(play-aeon self))))) |
@@ -0,0 +1,63 @@ | |||
(in-package #:subdecadence.utilities) | |||
;;; base-deck is the unshuffled deck | |||
;;; ♣ / C = Mj+ | |||
;;; ♠ / S = Mj- | |||
;;; ♥ / H = Mn+ | |||
;;; ♦ / D = Mn- | |||
(defvar +base-deck+ | |||
'("0♠" "0♣" "0♥" "0♦" | |||
"1♠" "1♣" "1♥" "1♦" | |||
"2♠" "2♣" "2♥" "2♦" | |||
"3♠" "3♣" "3♥" "3♦" | |||
"4♠" "4♣" "4♥" "4♦" | |||
"5♠" "5♣" "5♥" "5♦" | |||
"6♠" "6♣" "6♥" "6♦" | |||
"7♠" "7♣" "7♥" "7♦" | |||
"8♠" "8♣" "8♥" "8♦" | |||
"9♠" "9♣" "9♥" "9♦")) | |||
(defun remove-nth (seq n) | |||
"Remove the n-th element from the sequence `seq', returns a new sequence with the desired result, the function doesnt modify `seq'" | |||
(unless (typep seq 'list) (error "Type error: seq must be a sequence.")) | |||
(unless (typep n 'fixnum) (error "Type error: n must be a fixnum.")) | |||
(remove-if #'identity seq :start n :count 1)) | |||
(defun strip-suit (card) | |||
(unless (typep card 'string) (error "Type error: card must be a string.")) | |||
"Return the integer at the beginning of a card." | |||
(parse-integer (subseq card 0 1))) | |||
(defun diff (x y) | |||
(unless (typep x 'fixnum) (error "Type error: x must be a fixnum.")) | |||
(unless (typep y 'fixnum) (error "Type error: y must be a fixnum.")) | |||
(abs (- x y))) | |||
(defun display-cross (set) | |||
"Display 5 elements in Atlantean cross." | |||
(unless (typep set 'list) (error "Type error: set must be a list.")) | |||
(format t " | |||
~A | |||
~A ~A | |||
~A | |||
~A | |||
" | |||
(elt set 3) | |||
(elt set 2) | |||
(elt set 1) | |||
(elt set 0) | |||
(elt set 4))) | |||
(defun shuffle (deck) | |||
"Shuffle a list." | |||
(unless (typep deck 'list) (error "Type error: deck must be a list.")) | |||
(loop for i from (length deck) downto 2 | |||
do (rotatef (elt deck (random i (make-random-state t))) | |||
(elt deck (1- i)))) | |||
deck) |
@@ -0,0 +1,10 @@ | |||
(asdf:defsystem "subdecadence" | |||
:description "Automated subdecadence games in Common Lisp." | |||
:author "Ambery Rabbit" | |||
:version "0.4.2" | |||
:components | |||
((:module "src" | |||
:components ((:file "package") | |||
(:file "utilities") | |||
(:file "subdecadence") | |||
(:file "main"))))) |