Author: hhubner
Date: 2007-11-10 14:47:50 -0500 (Sat, 10 Nov 2007)
New Revision: 2264
Modified:
branches/trunk-reorg/projects/scrabble/src/game.lisp
branches/trunk-reorg/projects/scrabble/src/package.lisp
branches/trunk-reorg/projects/scrabble/src/rules.lisp
branches/trunk-reorg/projects/scrabble/src/start-webserver.lisp
branches/trunk-reorg/projects/scrabble/src/web.lisp
branches/trunk-reorg/projects/scrabble/website/scrabble.js
Log:
game play back end enhanced. move withdrawal untested.
Modified: branches/trunk-reorg/projects/scrabble/src/game.lisp
===================================================================
--- branches/trunk-reorg/projects/scrabble/src/game.lisp 2007-11-08 19:17:13 UTC (rev 2263)
+++ branches/trunk-reorg/projects/scrabble/src/game.lisp 2007-11-10 19:47:50 UTC (rev 2264)
@@ -11,26 +11,31 @@
(print-unreadable-object (tile-bag stream :type t :identity t)
(format stream "~A letters remaining" (remaining-tile-count tile-bag))))
+(defmethod shake-tile-bag ((tile-bag tile-bag))
+ (with-slots (tiles) tile-bag
+ (dotimes (i (fill-pointer tiles))
+ (let ((tmp (aref tiles i))
+ (random-index (random (fill-pointer tiles))))
+ (setf (aref tiles i) (aref tiles random-index))
+ (setf (aref tiles random-index) tmp)))))
+
+(defmethod initialize-persistent-instance :after ((tile-bag tile-bag))
+ (shake-tile-bag tile-bag))
+
(defun make-tile-bag (language)
(let ((tiles (make-array 102 :adjustable t :fill-pointer 0)))
(mapcar (lambda (entry)
- (destructuring-bind (char value count) entry
+ (destructuring-bind (letter value count) entry
(dotimes (i count)
- (vector-push-extend (make-tile char value) tiles))))
+ (vector-push-extend (make-tile letter value) tiles))))
(or (getf *tile-sets* language)
(error "language ~A not defined" language)))
- #+(or)
- (dotimes (i (fill-pointer tiles))
- (let ((tmp (aref tiles i))
- (random-index (random (fill-pointer tiles))))
- (setf (aref tiles i) (aref tiles random-index))
- (setf (aref tiles random-index) tmp)))
(make-object 'tile-bag :tiles tiles)))
(define-condition no-tiles-remaining (simple-error)
())
-(deftransaction draw-tile (tile-bag)
+(defun draw-tile (tile-bag)
(unless (plusp (remaining-tile-count tile-bag))
(error 'no-tiles-remaining))
(with-slots (tiles) tile-bag
@@ -38,31 +43,57 @@
(aref tiles (1- (fill-pointer tiles)))
(decf (fill-pointer tiles)))))
-(defun make-move (board placed-tiles)
- "Actually perform a move. BOARD contains the already placed tiles,
-PLACED-TILES contains the letters for the move to make. BOARD is
-modified to include the tiles placed. Returns the two values that
-CALCULATE-SCORE returns for the move."
- (check-move-legality board placed-tiles)
- (prog1
- (mapcar (lambda (word-result)
- (list (word-text word-result) (word-score word-result)))
- (words-formed board placed-tiles))
- (dolist (placed-tile placed-tiles)
- (put-letter board (tile-of placed-tile) (x-of placed-tile) (y-of placed-tile)))))
+(defun draw-tiles (tile-bag count)
+ (loop for i below count
+ collect (draw-tile tile-bag)))
+(defmethod undraw-tiles ((tile-bag tile-bag) tiles)
+ (dolist (tile tiles)
+ (vector-push-extend tile (tiles-of tile-bag)))
+ (shake-tile-bag tile-bag))
+
(defclass player (user)
((games :initform nil :accessor games-of))
(:metaclass persistent-class))
(defclass participant (store-object)
((player :initarg :player :reader player-of)
- (tray :initarg :tray :accessor tray-of))
+ (tray :initarg :tray :accessor tray-of)
+ (score :initform 0 :accessor score-of))
(:metaclass persistent-class))
+(defmethod print-object ((participant participant) stream)
+ (print-unreadable-object (participant stream :type t)
+ (format stream "~A score: ~A, ~A tile~:P"
+ (user-login (player-of participant))
+ (score-of participant)
+ (length (tray-of participant)))))
+
(defmethod tray-size ((participant participant))
(length (tray-of participant)))
+(defclass move (store-object)
+ ((participant :initarg :participant
+ :reader participant-of)
+ (placed-tiles :initarg :placed-tiles
+ :reader placed-tiles)
+ (new-tiles-drawn :initarg :new-letters-drawn
+ :reader new-tiles-drawn-of
+ :documentation "New letters that have been drawn after
+the move, should the move need to be undone")
+ (words-formed :initarg :words-formed
+ :reader words-formed-of)
+ (score :initarg :score
+ :reader score-of))
+ (:metaclass persistent-class))
+
+(defmethod print-object ((move move) stream)
+ (print-unreadable-object (move stream :type t)
+ (format stream "by ~A, ~A points (~{~A~^, ~})"
+ (player-of (participant-of move))
+ (reduce #'+ (mapcar #'cdr (words-formed-of move)))
+ (words-formed-of move))))
+
(defclass game (store-object)
((language :initarg :language
:reader language-of)
@@ -72,7 +103,10 @@
:accessor tile-bag-of)
(participants :initarg :participants
:accessor participants-of
- :documentation "List of participants in this game"))
+ :documentation "List of participants in this game")
+ (moves :initform nil
+ :accessor moves-of
+ :documentation "List of moves that have been made in this game"))
(:metaclass persistent-class))
(deftransaction make-game (language players)
@@ -94,16 +128,130 @@
:tile-bag tile-bag
:participants participants)))
+(defmethod next-participant-of ((game game))
+ (car (participants-of game)))
+
(defun participants-turn-p (game participant)
- (eq participant (car (participants-of game))))
+ (eq participant (next-participant-of game)))
(defun ensure-participants-turn (game participant)
- (assert (participants-turn-p game participant) nil
- "It's not ~s's turn."))
+ (unless (participants-turn-p game participant)
+ (error "It's not ~A's turn." (user-login (player-of participant)))))
-(deftransaction next-participants-turn (game)
- (with-accessors ((participants participants-of))
- game
- (let ((first (pop participants)))
- (setf participants (nconc participants (list first))))))
+(defun rotate-participants (game)
+ (with-slots (participants) game
+ (setf participants (append (cdr participants) (list (car participants))))))
+(defun unrotate-participants (game)
+ (with-slots (participants) game
+ (setf participants (append (last participants) (butlast participants)))))
+
+(defmethod letter-equal ((letter1 character) (letter2 character))
+ (eql letter1 letter2))
+
+(defmethod letter-equal ((letter1 character) (letter2 (eql nil)))
+ nil)
+
+(defmethod letter-equal ((tile1 tile) (tile2 tile))
+ (letter-equal (letter-of tile1) (letter-of tile2)))
+
+(defun ensure-participant-has-tiles (participant placed-tiles)
+ (let ((tray-letters (mapcar #'letter-of (tray-of participant)))
+ (placed-letters (mapcar (compose #'letter-of #'tile-of) placed-tiles)))
+ (dolist (letter placed-letters)
+ (let ((has-letter (find letter tray-letters :test #'letter-equal))
+ (has-blank (find nil tray-letters)))
+ (unless (or has-letter has-blank)
+ (error "participant ~A does not have tile ~A" participant letter))
+ (setf tray-letters
+ (if has-letter
+ (remove letter tray-letters :test #'letter-equal :count 1)
+ (remove nil tray-letters :key #'letter-of :count 1)))))))
+
+(defun remove-letters-from-participant-tray (participant tiles)
+ (let (removed-tiles)
+ (with-slots (tray) participant
+ (dolist (tile tiles)
+ (push (find tile tray :test #'letter-equal) removed-tiles)
+ (setf tray (remove tile tray :test #'letter-equal :count 1))))
+ removed-tiles))
+
+(defun draw-new-letters (tile-bag participant count)
+ (let ((drawn (draw-tiles tile-bag (min count (remaining-tile-count tile-bag)))))
+ (setf (tray-of participant)
+ (append drawn (tray-of participant)))
+ drawn))
+
+(defun make-move (game participant placed-tiles)
+ (ensure-participants-turn game participant)
+ (ensure-participant-has-tiles participant placed-tiles)
+ (check-move-legality (board-of game) placed-tiles)
+ (with-transaction (:make-move)
+ (let ((words-formed (mapcar (lambda (word-result)
+ (cons (word-text word-result) (word-score word-result)))
+ (words-formed (board-of game) placed-tiles))))
+ (dolist (placed-tile placed-tiles)
+ (put-letter (board-of game) (tile-of placed-tile) (x-of placed-tile) (y-of placed-tile)))
+ (let ((tiles-used (remove-letters-from-participant-tray participant (mapcar #'tile-of placed-tiles)))
+ (tiles-drawn (draw-new-letters (tile-bag-of game) participant (length placed-tiles)))
+ (score (reduce #'+ (mapcar #'cdr words-formed))))
+ (when (= 7 (length tiles-used))
+ (incf score 50))
+ (incf (score-of participant) score)
+ (push (make-object 'move
+ :participant participant
+ :placed-tiles placed-tiles
+ :new-tiles-drawn tiles-drawn
+ :words-formed words-formed
+ :score score)
+ (moves-of game))))
+ (rotate-participants game)))
+
+(defclass move-withdrawal (store-object)
+ ((participant :initarg :participant
+ :reader participant-of)
+ (reason :initarg :reason
+ :reader reason-of))
+ (:metaclass persistent-class))
+
+(defun withdraw-last-move (game reason)
+ (let ((move (car (moves-of game))))
+ (unless move
+ (error "no move in game to withdraw"))
+ (unless (typep game 'move)
+ (error "last move was not a letter placement, can't be withdrawn"))
+ (with-transaction (:withdraw-last-move)
+ (with-slots (participant placed-tiles new-tiles-drawn score) move
+ (decf (score-of participant) score)
+ (setf (tiles-of (tray-of participant))
+ (append (set-difference (tiles-of (tray-of participant))
+ new-tiles-drawn)
+ (mapcar #'tile-of placed-tiles)))
+ (undraw-tiles (tile-bag-of game) new-tiles-drawn)
+ (dolist (placement placed-tiles)
+ (put-letter (board-of game) nil (x-of placement) (y-of placement)))
+ (push (make-object 'move-withdrawal
+ :participant participant
+ :reason reason)
+ (moves-of game))))))
+
+(defclass tile-swap (store-object)
+ ((participant :initarg :participant
+ :reader participant-of)
+ (count :initarg :count
+ :reader count-of))
+ (:metaclass persistent-class))
+
+(defun swap-tiles (game participant tiles)
+ (unless (<= 7 (remaining-tile-count (tile-bag-of game)))
+ (error "not enough remaining tiles to swap"))
+ (with-transaction (:swap-tiles)
+ (setf (tray-of participant)
+ (append (set-difference (tray-of participant)
+ tiles)
+ (draw-tiles (tile-bag-of game) (length tiles))))
+ (undraw-tiles (tile-bag-of game) tiles)
+ (push (make-object 'tile-swap
+ :participant participant
+ :count (length tiles))
+ (moves-of game))))
Modified: branches/trunk-reorg/projects/scrabble/src/package.lisp
===================================================================
--- branches/trunk-reorg/projects/scrabble/src/package.lisp 2007-11-08 19:17:13 UTC (rev 2263)
+++ branches/trunk-reorg/projects/scrabble/src/package.lisp 2007-11-10 19:47:50 UTC (rev 2264)
@@ -11,7 +11,7 @@
"FIELD-TYPE"
"TILE"
- "CHAR-OF"
+ "LETTER-OF"
"VALUE-OF"
"BOARD"
@@ -29,6 +29,10 @@
"MAKE-TILE-PLACEMENTS"
"MAKE-MOVE"
+ "MOVE"
+ "SCORE-OF"
+ "PARTICIPANT-OF"
+ "WORDS-FORMED-OF"
"GAME"
"LANGUAGE-OF"
Modified: branches/trunk-reorg/projects/scrabble/src/rules.lisp
===================================================================
--- branches/trunk-reorg/projects/scrabble/src/rules.lisp 2007-11-08 19:17:13 UTC (rev 2263)
+++ branches/trunk-reorg/projects/scrabble/src/rules.lisp 2007-11-10 19:47:50 UTC (rev 2264)
@@ -60,7 +60,7 @@
(terpri stream)
(dotimes (x 15)
(dotimes (y 15)
- (format stream "~C " (aif (at-xy board x y) (char-of it) #\.)))
+ (format stream "~C " (aif (at-xy board x y) (letter-of it) #\.)))
(terpri stream))))
@@ -70,21 +70,21 @@
(defmethod at-placement ((board board) tile-placement)
(at-xy board (x-of tile-placement) (y-of tile-placement)))
-(deftransaction put-letter (board tile x y)
+(defun put-letter (board tile x y)
(setf (aref (placed-tiles-of board) x y) tile))
(defclass tile (store-object)
- ((char :reader char-of :initarg :char)
+ ((letter :reader letter-of :initarg :letter)
(value :reader value-of :initarg :value))
(:metaclass persistent-class))
(defmethod print-object ((tile tile) stream)
(print-unreadable-object (tile stream :type t :identity nil)
- (with-slots (char value) tile
- (format stream "~A (~A)" char value))))
+ (with-slots (letter value) tile
+ (format stream "~A (~A)" (when letter (char-name letter)) value))))
-(defun make-tile (char value)
- (make-object 'tile :char char :value value))
+(defun make-tile (letter value)
+ (make-object 'tile :letter letter :value value))
(defmethod placed-tile-adjacent ((board board) (tile-placement tile-placement))
"Check whether the given TILE-PLACEMENT on the board is adjacent to
@@ -197,5 +197,5 @@
(defun word-text (word-result)
"Convert the letter in a word result returned by WORDS-FORMED to a
string."
- (coerce (mapcar (compose #'char-of #'car) word-result) 'string))
+ (coerce (mapcar (compose #'letter-of #'car) word-result) 'string))
Modified: branches/trunk-reorg/projects/scrabble/src/start-webserver.lisp
===================================================================
--- branches/trunk-reorg/projects/scrabble/src/start-webserver.lisp 2007-11-08 19:17:13 UTC (rev 2263)
+++ branches/trunk-reorg/projects/scrabble/src/start-webserver.lisp 2007-11-10 19:47:50 UTC (rev 2264)
@@ -3,15 +3,18 @@
(defclass scrabble-store (mp-store random-mixin)
())
-(defun open-scrabble-store ()
+(defun open-scrabble-store (&optional delete-old-p)
(ignore-errors (close-store))
- (asdf:run-shell-command "rm -rf /tmp/scrabble-store/")
+ (when delete-old-p
+ (sb-ext:run-program "/bin/rm" '("-rf" "/tmp/scrabble-store/") :environment nil))
(make-instance 'scrabble-store :directory "/tmp/scrabble-store/"
:subsystems (list (make-instance 'store-object-subsystem)
(make-instance 'random-mixin-subsystem)))
- (let ((user1 (make-user "user1" :class 'player :full-name "User Eins"))
- (user2 (make-user "user2" :class 'player :full-name "User Zwei")))
- (make-game :de (list user1 user2))))
+ (unless (class-instances 'user)
+ (format t "creating test users and game~%")
+ (let ((user1 (make-user "user1" :class 'player :full-name "User Eins"))
+ (user2 (make-user "user2" :class 'player :full-name "User Zwei")))
+ (make-game :de (list user1 user2)))))
(defparameter *website-directory*
(make-pathname :name nil :type nil :version nil
Modified: branches/trunk-reorg/projects/scrabble/src/web.lisp
===================================================================
--- branches/trunk-reorg/projects/scrabble/src/web.lisp 2007-11-08 19:17:13 UTC (rev 2263)
+++ branches/trunk-reorg/projects/scrabble/src/web.lisp 2007-11-10 19:47:50 UTC (rev 2264)
@@ -27,18 +27,29 @@
(defmethod encode-json ((tile-bag tile-bag) stream)
(encode-json-plist (list :remaining-tiles (remaining-tile-count tile-bag)) stream))
+(defmethod encode-json ((move move) stream)
+ (encode-json-plist (list :participant-login (user-login (player-of (participant-of move)))
+ :score (score-of move)
+ :words (mapcar (lambda (word-cons)
+ (list :word (car word-cons)
+ :score (cdr word-cons)))
+ (words-formed-of move)))
+ stream))
+
+
(defmethod encode-json ((board board) stream)
(princ #\[ stream)
(dotimes (x 15)
(dotimes (y 15)
(awhen (at-xy board x y)
- (encode-json (list x y (char-of it) (value-of it)) stream)
+ (encode-json (list x y (letter-of it) (value-of it)) stream)
(princ #\, stream))))
(princ #\] stream))
(defmethod encode-json ((participant participant) stream)
(start-session)
- (encode-json-plist (append (list :name (user-full-name (player-of participant))
+ (encode-json-plist (append (list :login (user-login (player-of participant))
+ :name (user-full-name (player-of participant))
:remaining-tiles)
(list (if (equal (user-login (player-of participant))
(session-value :user))
@@ -66,20 +77,27 @@
(:tr (:td "Password") (:td (:input :type "PASSWORD" :name "password")))
(:tr (:td) (:td (:input :type "SUBMIT")))))))))
-(defun parse-move (tray string)
+(defun parse-move (participant string)
"Given a string X1,Y1,LETTER1,X2,Y2,LETTER2..., return a list of
-moves ((X1 Y1 LETTER-TILE2) (X2 Y2 LETTER-TILE2) ...)"
- (let (list-of-moves)
+moves ((X1 Y1 LETTER-TILE2) (X2 Y2 LETTER-TILE2) ...). LETTERx may
+either be a single-character letter which will be used directly or a
+character name (like LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS) which will
+be converted into a character using NAME-CHAR."
+ (let ((tray (tray-of participant))
+ list-of-moves)
(labels
((use-letter (letter)
- (awhen (find letter tray :key #'char-of)
+ (awhen (or (find letter tray :key #'letter-of)
+ (find nil tray :key #'letter-of))
(setf tray (remove it tray))
(return-from use-letter it))
- (error "tray does not contain letter ~A" letter))
+ (error "tray of ~A does not contain letter ~A" participant letter))
(recurse (x-string y-string letter &rest more)
(push (list (parse-integer x-string)
(parse-integer y-string)
- (use-letter (aref letter 0)))
+ (use-letter (if (= 1 (length letter))
+ (aref letter 0)
+ (name-char letter))))
list-of-moves)
(when more
(apply #'recurse more))))
@@ -97,13 +115,18 @@
(define-easy-handler (make-move-handler :uri "/make-move" :default-request-type :post)
(move game)
(start-session)
- ;; MOVE contains the move to make. (This should) check that it is
- ;; the session users' turn, that the move is legal, then actually
- ;; make the move.
- (let* ((game (find-game game))
- (participant (find (find-user (session-value :user)) (participants-of game) :key #'player-of)))
- (scrabble:make-move (board-of game)
- (parse-move (tray-of participant) move))))
+ ;; MOVE contains the move to make, GAME is the object ID of the game.
+ (with-output-to-string (s)
+ (handler-case
+ (progn
+ (let* ((game (find-game game))
+ (participant (find (find-user (session-value :user)) (participants-of game) :key #'player-of)))
+ (scrabble:make-move game
+ participant
+ (parse-move participant move))
+ (encode-json-plist (list :game game) s)))
+ (error (e)
+ (encode-json-plist (list :error (princ-to-string e)) s)))))
(define-easy-handler (games :uri "/games") ()
(start-session)
Modified: branches/trunk-reorg/projects/scrabble/website/scrabble.js
===================================================================
--- branches/trunk-reorg/projects/scrabble/website/scrabble.js 2007-11-08 19:17:13 UTC (rev 2263)
+++ branches/trunk-reorg/projects/scrabble/website/scrabble.js 2007-11-10 19:47:50 UTC (rev 2264)
@@ -31,10 +31,59 @@
["triple-word",null,null,"double-letter",null,null,null,"triple-word",
null,null,null,"double-letter",null,null,"triple-word"]];
+// Scrabble rule enforcement
+
+function checkMoveLegality(placedTiles)
+{
+ // Given the board and list of placed tiles, either throw an error or
+ // return if the move is legal.
+
+ var positions = map(function (placement) { return [ placement[0], placement[1] ] }, placedTiles)
+ .sort(function (a, b) { (a[0] > b[0]) || (a[1] > b[1])});
+
+ if (filter(partial(operator.ne, positions[0][0]), map(function (position) { return position[0] }, positions)).length
+ && filter(partial(operator.ne, positions[0][1]), map(function (position) { return position[1] }, positions)).length) {
+ throw "not-in-a-row";
+ }
+
+ var startOfPlacement = positions[0];
+ var endOfPlacement = positions[positions.length - 1];
+
+ for (var x = startOfPlacement[0]; x <= endOfPlacement[0]; x++) {
+ for (var y = startOfPlacement[1]; y <= endOfPlacement[1]; y++) {
+ if (!letterAt(x, y) && (findValue(positions, [ x, y ]) == -1)) {
+ throw "placement-with-holes";
+ }
+ }
+ }
+
+ if (findValue(positions, [ 7, 7 ]) == -1) {
+ var found = false;
+ for (var x = startOfPlacement[0]; !found && x <= endOfPlacement[0]; x++) {
+ for (var y = startOfPlacement[1]; !found && y <= endOfPlacement[1]; y++) {
+ if (((x > 0) && letterAt(x - 1, y))
+ || ((x < 14) && letterAt(x + 1, y))
+ || ((y > 0) && letterAt(x, y - 1))
+ || ((y < 14) && letterAt(x, y + 1))) {
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ throw "not-touching-other-tile";
+ }
+ }
+}
+
+
+//
+
function getFieldScore(x, y) {
return boardScoring[x][y] || 'standard';
}
+var theirTrays;
+
var gameID = 108;
var board;
@@ -67,6 +116,13 @@
setElementPosition(myTrayContainer, { x: border + 194, y: border + 665 });
appendChildNodes(container, myTrayContainer);
+ theirTrays = DIV();
+ theirTrays.style.position = 'absolute';
+ theirTrays.style.width = 7 * 44 + 'px';
+ theirTrays.style.height = '70px';
+ setElementPosition(theirTrays, { x: border + 16 * 40, y: border + 40 });
+ appendChildNodes(container, theirTrays);
+
var shuffleButton = DIV(null, "shuffle");
shuffleButton.style.color = 'white';
shuffleButton.style.position = 'absolute';
@@ -176,9 +232,15 @@
var move = [];
function makeMove(x, y, letter) {
- move.push([x, y, letter]);
+ move[move.length] = [x, y, letter];
$('move').onclick = submitMove;
$('move').innerHTML = move.toString();
+ try {
+ checkMoveLegality(move);
+ }
+ catch (e) {
+ $('move').innerHTML = e.toString();
+ }
}
function clearMove() {
@@ -197,9 +259,21 @@
res.addCallbacks(moveSuccess, moveFailure);
}
-function moveSuccess()
+function moveSuccess(result)
{
- clearMove();
+ var response;
+ try {
+ response = eval('(' + result.responseText + ')');
+ }
+ catch (e) {
+ alert("invalid JSON reply: " + result.responseText);
+ return;
+ }
+ if (response.error) {
+ alert(response.error);
+ } else {
+ clearMove();
+ }
}
function moveFailure(e)
@@ -207,8 +281,12 @@
alert('failed: ' + e);
}
+var specialKeyCodes = { 59: 'LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS',
+ 192: 'LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS',
+ 222: 'LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS' };
+
function letterKeyPressed(type, args, obj) {
- var letter = String.fromCharCode(args[0]);
+ var letter = specialKeyCodes[args[0]] || String.fromCharCode(args[0]);
var x = cursor.x;
var y = cursor.y;
cursor.advance();
@@ -310,6 +388,13 @@
tray = newTray;
}
+function addTheirTray (participant) {
+ appendChildNodes(theirTrays, DIV(null,
+ DIV(null, participant.name),
+ DIV(null, map(function () { return IMG({ src: 'images/NIL.png' }) },
+ new Array(participant.remainingTiles)))));
+}
+
function drawGameState (gameState) {
for (var i = 0; i < gameState.board.length; i++) {
var x = gameState.board[i][0];
@@ -317,19 +402,29 @@
var char = gameState.board[i][2];
setLetter(x, y, char);
}
+ for (var i = 0; i < gameState.participants.length; i++) {
+ var participant = gameState.participants[i];
+ if (typeof participant.remainingTiles == 'number') {
+ addTheirTray(participant);
+ } else {
+ makeMyTray(map(function (entry) { return entry.letter }, participant.remainingTiles));
+ }
+ }
}
-var legalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜß".split("");
+var legalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
function init() {
makeBoard();
- var d = loadJSONDoc("/game/" + gameID);
- d.addCallbacks(drawGameState, alert);
var letterKeyCodes = [];
for (var i = 0; i < legalLetters.length; i++) {
letterKeyCodes[i] = legalLetters[i].charCodeAt(0);
}
+ // add mozilla key codes
+ letterKeyCodes.push(59); // u"
+ letterKeyCodes.push(192); // o"
+ letterKeyCodes.push(222); // a"
var letterKeyListener = new YAHOO.util.KeyListener(document,
{ keys: letterKeyCodes },
{ fn: letterKeyPressed, scope: this, correctScope: true });
@@ -345,6 +440,6 @@
moveDisplay.style.position = 'absolute';
setElementPosition(moveDisplay, { x: border + 550, y: border + 665 });
appendChildNodes(document.body, moveDisplay);
- var d = loadJSONDoc("/game/108");
+ var d = loadJSONDoc("/game/" + gameID);
d.addCallbacks(drawGameState, alert);
}