Reputation: 1231
I am not sure if I am missing something very basic here, but I want to read in a string from a file and use it in my later program as a list of symbols, i.e.
"8C TS"
should become ((8 C) (T S))
I know that I can split the initial string using the split-sequence
library without problems, but as a string is a sequence of characters I end up with
> (loop :for c :across "8C" :collect c)
(#\8 #\C)
Is it possible to convert the initial string as specified above or is there some reason why this should not/could not be done?
Upvotes: 0
Views: 417
Reputation: 51501
If you want to represent cards as a generic datastructure, you might as well use a vector instead of a list. A vector of characters is just a string, so (split-sequence #\space hand)
, which gives ("8C" "TS")
, should be enough. You'd define a hand to be a list of cards, a card a string of length 2 containing value and suit, and value and suit as characters.
You then use simple readers to access the attributes:
(defun card-value (card)
(aref card 0))
(defun card-suit (card)
(aref card 1))
If you want a more explicit approach, you might prefer defining classes or structs for each:
(defclass hand ()
((cards :initarg :cards
:reader hand-cards)))
(defclass card ()
((value :initarg :value
:reader card-value)
(suit :initarg :suit
:reader card-suit)))
Parsing creates such objects:
(defun read-hand (string &aux (upcased (string-upcase string)))
(make-instance 'hand
:cards (mapcar #'read-card
(split-sequence #\space upcased))))
(defun read-card (string)
(make-instance 'card
:value (case (aref string 0)
(#\T 10)
(#\J 11)
(#\Q 12)
(#\K 13)
(#\A 14)
(t (parse-integer (string (aref string 0)))))
:suit (intern (aref string 1) '#:keyword))
This would represent the value as an integer and the suit as a keyword. You might then want to define predicates like card=
, card-suit-=
, card-value-<
etc.
Upvotes: 2