Skip to content

Commit 910da8b

Browse files
Use Strings as keys in Lisp.
Twice as slow as previous solution.
1 parent 2bb121a commit 910da8b

File tree

1 file changed

+51
-22
lines changed

1 file changed

+51
-22
lines changed

src/lisp/main.lisp

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,65 @@
77
(declaim (optimize (speed 3) (debug 0) (safety 0)))
88
(setq *block-compile-default* t)
99

10-
(declaim (inline nth-digit char->digit))
10+
(declaim (inline nth-digit char->digit digitp))
1111

12-
(declaim (ftype (function (string (unsigned-byte 8)) (unsigned-byte 8)) nth-digit))
12+
(declaim (ftype (function (simple-string (unsigned-byte 8)) string) nth-digit))
1313
(defun nth-digit (digits i)
1414
"The i-th element of a character string of digits, as an integer 0 to 9."
15-
(- (char-code (char digits i)) #.(char-code #\0)))
15+
(ecase (char digits i)
16+
((#\0) "0")
17+
((#\1) "1")
18+
((#\2) "2")
19+
((#\3) "3")
20+
((#\4) "4")
21+
((#\5) "5")
22+
((#\6) "6")
23+
((#\7) "7")
24+
((#\8) "8")
25+
((#\9) "9")))
1626

17-
(declaim (ftype (function (base-char) (unsigned-byte 8)) char->digit))
27+
(defmacro scase (s &rest cases)
28+
(cons 'or (loop for c in cases
29+
collect (list 'if (list 'string= s (car c)) (cadr c) ))))
30+
31+
(declaim (ftype (simple-string) boolean) digitp)
32+
(defun digitp (s)
33+
(and
34+
(= 1 (length s))
35+
(scase s
36+
("0" t)
37+
("1" t)
38+
("2" t)
39+
("3" t)
40+
("4" t)
41+
("5" t)
42+
("6" t)
43+
("7" t)
44+
("8" t)
45+
("9" t))))
46+
47+
(declaim (ftype (function (base-char) simple-string) char->digit))
1848
(defun char->digit (ch)
1949
"Convert a character to a digit according to the phone number rules."
2050
(ecase (char-downcase ch)
21-
((#\e) 0)
22-
((#\j #\n #\q) 1)
23-
((#\r #\w #\x) 2)
24-
((#\d #\s #\y) 3)
25-
((#\f #\t) 4)
26-
((#\a #\m) 5)
27-
((#\c #\i #\v) 6)
28-
((#\b #\k #\u) 7)
29-
((#\l #\o #\p) 8)
30-
((#\g #\h #\z) 9)))
51+
((#\e) "0")
52+
((#\j #\n #\q) "1")
53+
((#\r #\w #\x) "2")
54+
((#\d #\s #\y) "3")
55+
((#\f #\t) "4")
56+
((#\a #\m) "5")
57+
((#\c #\i #\v) "6")
58+
((#\b #\k #\u) "7")
59+
((#\l #\o #\p) "8")
60+
((#\g #\h #\z) "9")))
3161

32-
(declaim (ftype (function (string) integer)))
62+
(declaim (ftype (function (simple-string) simple-string)))
3363
(defun word->number (word)
3464
"Translate a word (string) into a phone number, according to the rules."
35-
(let ((n 1)) ; leading zero problem
36-
(declare (type integer n))
65+
(let ((n ""))
3766
(loop for i from 0 below (length word)
3867
for ch = (char word i) do
39-
(when (alpha-char-p ch) (setf n (+ (* 10 n) (char->digit ch)))))
68+
(when (alpha-char-p ch) (setq n (concatenate 'string n (char->digit ch)))))
4069
n))
4170

4271
(defglobal *dict* nil
@@ -66,26 +95,26 @@
6695
(format t "~a:~{ ~a~}~%" num (reverse words))
6796
(let ((next-iterations
6897
(do ((i start (1+ i)) ; var, initial value, increment per iteration
69-
(n 1)
98+
(n "")
7099
(max (length digits))
71100
(result nil))
72101
((>= i max) result) ; exit condition and return-value
73-
(setq n (+ (* 10 n) (nth-digit digits i)))
102+
(setq n (concatenate 'string n (nth-digit digits i)))
74103
(let ((next-words (gethash n *dict*)))
75104
(when next-words (push (list (1+ i) next-words) result))))))
76105
(if next-iterations
77106
(loop for (i next-words) in next-iterations do
78107
(loop for word in next-words do
79108
(print-translations num digits i (cons word words))))
80-
(when (not (numberp (first words)))
109+
(when (not (digitp (first words)))
81110
(print-translations num digits (+ start 1)
82111
(cons (nth-digit digits start) words)))))))
83112

84113
(defun load-dictionary (file size)
85114
"Create a hashtable from the file of words (one per line). Takes a hint
86115
for the initial hashtable size. Each key is the phone number for a word;
87116
each value is a list of words with that phone number."
88-
(let ((table (make-hash-table :test #'eql :size size)))
117+
(let ((table (make-hash-table :test #'equal :size size)))
89118
(with-open-file (in file)
90119
(loop for word = (read-line in nil) while word do
91120
(push word (gethash (word->number word) table))))

0 commit comments

Comments
 (0)