Martin Buchmann
Martin Buchmann

Reputation: 1231

How to convert a string to a list of symbols?

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

Answers (1)

Svante
Svante

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

Related Questions