I got a crash (fatal exception on shutdown) in a two-device game where my dictionary had lost to the host's. Figure out why. Ask if people prefer the turn to automatically jump to the next player or remain where they can see what new tiles they got. In the former case they'll have to reenter their password before they can see what tiles they received. In the latter the new player has to click the H and then T buttons to get to the same point he'd otherwise be at (but would have to enter his password either way.) Also ask: do you want tiles the same color as score as a further hint at whose tray is revealed? On B&W, is some further hint needed? Maybe inverting the thing? Bold's not all that subtle, 'specially on the color display. Bringing up a hint window when Trade window is up but not obscuring that window causes the cursor to be drawn over the trade window (if that's where it is.) I'm erasing the cursor before calling the engine. XW3 puts it in the right place after adding the tiles the engine found. Can I do that? Don't bother. XW3 doesn't do all that great a job once you hit the hint button a few times. Just hide it for good once the robot wants to overwrite it and make the user put it back. Tap on "T" button should: pick the first local and non-robot player (counting from the current turn), make him selPlayer, and show his tray. If he's the only local & nonRobot it should also reveal it immediately (but this logic belongs elsewhere in the generic revealing code if it's not already there). Do something similar after turn change? No; just hide the tray In robot vs human game, I had board fail to scroll robot's move into view. I'd done some manual scrolling; perhaps it was out of sync and thought it was in view? Why does scrolling invalidate the tray? B/c palm calls board_invalAll in response to scroll. Does there need to be a "cellsOnly" param to that function? It'd be useful from one call site in board.c as well... Choose some subtle background color for tiles vs board, and honor it. Add error message when you try to peek at a remote player's tiles. When hide tray and board is scrolled, need to unscroll it before hiding scrollbar! At least when lefty's not on. Show local user on guest machine on new game Number of players should default to 1 when "guest" selected. When new game comes up, should default to showing the tiles of the first non-remote player. Add a printf method on stream; useful to cleanup comms_getStats and probably for history. What happens if a user sends off a turn, and then undoes it before the server sends back the confirmation and new tiles? Worse, what if he sends a second move for the same turn? Make sure you can deal with this!! Maybe commiting to the user's model early is the right fix? When robot->non-robot halfway through a search hilited squares remain. Problems with password getting updated and stored from options dlg? Looks as if it's not checking the current one. For alpha: 0) Handle case where dictionaries don't match. * Get rest of ir status msg showing up in dlog. 1) Look into getting robot move to show up before the device communicates it to the server/turn advances. This is probably a matter of getting draw called earlier in the process, assuming the invals are happening at the right time. They *are* happening twice. If try to look at robot's tiles, get into infinite loop where keeps saying you can't. In emulator: new game with robot first. Robot makes move. Now with robot's tiles still "showing" press the hint button. Whether a player is a robot or not shouldn't be transmitted over the wire. We don't want to get out of sync when it's changed??? IR_STATE_DOLAP is state, but there's nothing on the send queue. This is on the reciever side, so of course there's nothing. So why DOLAP? Seem to be calling IrConnectIrLap after LAP_ESTAB What to do when discovery fails? Same "retry/abort" message? Make it so that IR doesn't loop forever when can't send. That means that when user says cancel we forget we ever saw that message, purging it from the queue and allowing IR to shut down from its current state. User will have to use the resend button to restart the process. We don't want to be calling the IR code (and asking for nil events) all the time an IR game is in progress. So what's the desired idle state for a device when no messages are being sent or expected. It needs to be something that can be changed by the device, so expectation can't be part of it: we need to be able to receive a message at any time. That state is simply having done a bind: at that point an incomming message will be received. So do_ir_work need only be called if 1) there's a message waiting to be sent; OR 2) we've received notification of an incomming message; or 3) we're in some state involved in processing incomming or outgoing messages. It appears that either side needs to do the discovery process before sending a message -- i.e. that having received a message doesn't absolve the server from doing it before it can send its first. So let's make that part of every send! The state transitions for a send look like this: Main steps/actions Intermediate steps DISCOVERY IR_STATE_DO_DISCOVERY, IR_STATE_REDO_DISCOVERY, IR_STATE_DISCOVERY_SENT, IR_STATE_DISCOVERY_COMPLETE, IRLAP IR_STATE_LAP_SENT IR_STATE_DOLMP LMP IR_STATE_CONNECTREQ_SENT IR_STATE_SEND_READY <---+ SEND | IR_STATE_SEND_DONE ---+ IR_STATE_CAN_DISCONNECT IRLAP_DISCON And for a receipt (state starts out bound, which is all that's needed) SIGNALING IR_STATE_CONN_INCOMMING IR_STATE_MESSAGE_RECD IR_STATE_CAN_DISCONNECT deviceIndex is not comming back -1, and so nDevices isn't getting incremented. Look at what happens on first game, and then on new game NewGame is broken (gtk and palm). Players aren't getting tiles. Loading dicts and saved games: we don't want to save the whole word list. But we do want to save the tile info that (perhaps) came over in the initial message from the server. And on palm we need to make sure that *if* a local dictionary was in use it's used again. So the name of the dict must be preserved. In the dict. Ideally, then, a dict would internalize itself by going out on "disk" and finding the word data and lo that. The model currently does everything from the pending tiles area. model_commitTurn expects tiles to be in that space first. And the fromStream call? Likewise, it expects the tray to already contain the tiles being moved (a reasonable assumption) and moves them one at a time to the board via model_moveTrayToBoard(). Anytime I want to load a game from the stack I need a model. So I'll have the tray. Can I then insert the stack between the board and the players' trays: loading a move from the stack means copying the moved tiles from the stack first to the tray, then calling an existing method to move them to the board. I'd want to factor the current code for loading from a stream to use the same code as loading from a stack entry. Which leads to the next question: Should the stack be an in-memory stream? I need bitwise putters and getters on streams anyway. If the stream had seek/tell functionality then the "stack" entry for a move or trade might only need to be a cookie that would seek the stack's stream to the beginning of the data. Order of tiles in played part of stack matters. stack[0] = {type=INITIAL;playerN=0;nAssigned=7;assigned[0..6]='AECFQAG'}; stack[1] = {type=INITIAL;playerN=1;nAssigned=7;assigned[0..6]='XFEGEDG'}; stack[2] = {type=INITIAL;playerN=2;nAssigned=7;assigned[0..6]='KILLERS'}; stack[3] = {type=MOVE;playerN=0;startCol=7;startRow=7;direction=HORIZ;nPlayed=4;nAssigned=7;played[0..3]='CAFE';assigned[0..3]='HYTO'}; stack[4] = {type=MOVE;playerN=1;startCol=7;startRow=5;direction=VERT;nPlayed=2;nAssigned=2;played[0..1]='FG';assigned[0..3]='WI'}; stack[5] = {type=TRADE;playerN=2;nTraded=7;traded[0..6]='KILLERS';assigned[0..3]='IBIDIEK'}; stack[6] = {type=MOVE;playerN=0;startCol=4;startRow=7;direction=HORIZ;nPlayed=4;nAssigned=4;played[0..3]='FGEE';assigned[0..3]='FEWI'}; // challenge is against a word, which is identified by its start column // and row and direction. player number is optional. stack[7] = {type=CHALLENGE;playerN=2;targetCol=4,targetRow=7;direction=HORIZ}; Should I hack something in to show what the most recent move is? The complete stack will take some time, particularly if I want to change the protocol to include the faces as well as the count of tiles assigned to each player on each device. If not, the tasks look like this: 1. Start sending all tiles to all devices. Make sure the models can handle this, that they don't reveal what they shouldn't. 2. Create an undo stack and start putting moves into it. That'll take some serious factoring of server code, which currently moves one tile at a time from tray to board. There probably needs to be some intermediate form that holds all the tiles to be moved at once; the same function to move that set of tiles to the board could be called in a loop to update the model from the stack once the stack becomes what's externalized. 3. Switch from externalizing the whole board to just the stack. 4. Add code rendering the most recent move differently from everything else. At this point the thing becomes demoable. :-) Next task: need to get most recent move showing in white-on-black. That should make the stuff demoable. What info goes in the undo stack, and on which devices? There is a style of documenting a game that includes at every turn no only what tiles a player played but also what he considered playing but didn't. To enable that, I need to let the model on every device know the whole story. And to put deals as well as moves on the stack. BUG: start server and client. quit and restart client. make move on server and send to client. Never shows up on client's board. Does it even get the message? What about dictionary? Do we save it as part of the file stream? Surely not the whole thing. So some dictionary has to be passed in at startup to the main app (rather than read from the file). But we want to save the letters part of the dict so that it doesn't need to be exchanged from server to client over the net every time the client starts up again. So: the tile count/value part of a dict must be saved in the stream. We'll pass the dict that comes in on the command line to the model's "read from stream" method. It may be null. The model will need to read a dict from the stream anyway. If it was passed a non-null one, it needs to assert that they're equivalent. turn is getting changed between where it's set in line 91 of tray.c Channel assignment. There must be agreement among all the comms modules as to what device matches what channel. Each client starts up by pushing a hostname and port into its comms structure. This will be used for communications when the message's channel is still 0, e.g. for the first outgoing message. As the server gets incomming messages, it sees that they have no channel number and assigns them one along with associating their addresses with the channel number. Each conversation with between a server and client takes place over a "channel". A channel is assigned by the comms module when it encounters a message whose channel number is 0. The server keeps track of clients by address, but the address is nothing but a channel number. The server knows the channel number So I've got a simple message from client to server working. Next I need to harvest the return address into the comms module somehow and use it to send back to the client. Client needs to be ready to receive. And the way the return address is saved needs to be savable and yet resettable by the user eventually -- if it stops working, for example, then allowing the user to specify a new address might be one response. How does it start? * Client knows server address. It's built into the stream. Or in a comms connection. When the client closes the stream, it gets "sent", which means it's queued up. How does the sending code know where to send it? The address is obtainable from the stream. Need to think hard about messaging protocol. Think about saving a game midway through to drive some of the requirements. And use UDP on unix to force thinking about unreliable/un-ACKed transport. * Messages need sequence numbers. Process incomming only in order. (What does order mean when there's a server talking to two machines?) Drop messages out of order. No ACK -- b/c doesn't exist in SMS due to cost. * Saved state includes next expected message. When start up after being saved, use that to get back to looking for the right message. Sender needs to save the last sent message, and to possibly resend when recipient restarts and indicates hasn't received it. * Is there a way to support ACK where it's cheap and easy (IR, UDP) but not require it where it's expensive (SMS)? Game start: server expects clients and is listening. Client sends message. server registers client, adds client's players, and harvests client address for future sends. Server keeps track of a number *and* address for each message, so there might be two Msg#2s sent, but never to the same client. Similarly, server might receive two Msg#3s, but from different clients. Arrow bitmaps for palm need to have transparent backgrounds, if possible. use destructor for non-palm dictionaries too Franklin: don't keep drawing progress rects when new game dialog, etc., is up. Don't allow a player to ask for a hint when he has another in progress. Or rather: stop any in progress when one is requested. I'm not sure whether it should be allowed for each player to be running one at the same time, or even for one player to be running one at the same time as the robot is. If I do allow this, I need to be prepared for the hints to include illegal moves since the board will have been changed by the robot's making its move. For Franklin alpha: don't show backs of tiles when only one player or when only one non-robot player Franklin: need to be able to interrupt robot. (Ask tech list how to do an EventAvail()) Franklin: Need to be able to start a new game without quitting. [ What does starting a new game mean? In the model it's easy: empty the board and the trays. But for the server? There need to be two ways of starting a new game, one with the same players (some remote), and another meaning expect new players to connect. Maybe this can all be accomplished with a NewGames dialog. I bring the dialog up, and it shows all the players with their names, whether they're robots, and their network addresses (however that's expressed). Maybe I need in gtk to add a newGames dialog so I can experiment with all this stuff. It'd be nice to be able to change whether I'm client or server without restarting the app. This implies that server has to be reinitialized completely, or maybe recreated. Start by designing the dialog in GTK.... ] move getMiniWText from drawCtxt to util? Use snprintf instead of sprintf Franklin: draw routines should normally draw to an offscreen bitmap, which Draw should copy to the screen. This would speed recovery from dialogs that don't save the bits behind. It'd have to be possible to cause the drawcontext methods to write directly to the screen buffer, though, for the invertRect calls that happen during robot searches. To copy a screen buffer each time would be too slow. Don't change the selPlayer field in board.c when a turn's over so that player can check out his new tiles, etc. first. Turn transition: when a player completes a move or a turn, he'd probably like to be able to take a quick look at the new tiles he's been given. Now I move to the next player automatically, forcing him to move back to his own tray, using the password if there is one, before hiding it again and handing over the machine -- or to wait for the robot to finish its next move. Better to not change whose tray is displayed, forcing players to hide their trays before handing over the device. The only problem becomes how to tell the robot its its turn to move. So on a turn change, we advance the server's notion of whose move it is, but not the board's of selPlayer. Then if I just finished and want the robot to move, I can hide my tray. On tray-hide, then, the board needs to check if the server wants time? Hmmmm. currently, server requests time for the robot inside server_commitTrade if the robot's next. Instead I'd need to skip this, and instead have the board run a similar test when the tray's hidden or at some other time. Hmmm. I think there's a distinction between tray hidden (allows full view of the board where they overlap) and tray reversed, which is the way the tray should be revealed to someone who's doesn't know the password. When the tray's reversed, you can still tell how many tiles are in it. Maybe hidden doesn't ever happen when there's no overlap between board and tray. On devices where there is overlap, there needs to be a way to do both. Client (gtk) *sometimes* comes up undrawn. Make robot trade when can't find a good score (see 3.2 criteria) Add vtable to dict with at least destroy(); and use from server.c Make a GTK option to put the scoreboard beside the board, as it might be on an Epoc R5 screen. Don't allow a hint when board hidden (or: reveal it; see what 3.1 does in this case) (Is it possible that the notion of pending tiles belongs only in the board? Board can easily draw that stuff; engine and scoring shouldn't need to filter it out. Board could keep a MoveInfo struct for each player.) If pending tiles live in the board, then what does a commit look like? Now, the server tells the model to "commit" pending tiles. If I change this, then the board must do something like load the pending tiles into a MoveInfo struct, check their legality, and then pass them to the server for commiting. Also, scoring will change in a big way; now the model is expected to contain everything it needs. Instead, a MoveInfo struct needs to get passed in at every point. But I think this is better: we're scoring an outside quantity against the current state. All robots share same engine; give player engine only when first used. Separate the parts of engine used only during a search from those maintaining state so that they don't get duplicated. Add ability for each player to have own dictionary? Franklin/engine: add mid-search robot cancel Verify that scoring is accurate, perhaps by making all tiles and bonuses worth 1 for a while so visual checks are trivial. Make possible a robot vs. robot game across the net It'd be nice to be able to identify a cell with a move, e.g. as the old version does in keeping the moves in made order. This would allow, for example, to hilite the most recent move, and to draw in different colors the moves made by different players. What'd be needed is an undo stack, with moves added each turn -- but also trades (and challenges) so that the whole undo/redo metaphor can be provided. Once this is there, then drawing the board is a two-step process. The first loop goes through all the cells and draws only those that are empty. The second goes through the undo stack and draws cells in the order in which they were filled, passing in the player number. In both cases the cell isn't drawn unless it's dirty. (Challenges might be implemented as an agreement whereby the player simply undoes his move and replaces it with a PASS; there doesn't necessarily have to be a CHALLENGE entry on the undo stack.) Add a mode so people can create an in-progress game and then jump into it. I guess this really means that people need to be able to write directly to the board irrespective of what's in their trays, and also that they need to be able to put what they want in their trays. Dale Dreher : How about calculating the players' "XQ,Xword Quotient". XQ=(final player score)/(total face value of the tiles the player played). ME: maybe this shows up in a drop-down (along with player name) when you timer-tap the scoreboard entry? ajiet.holtkamp@t-online.de: Why is everyone asked if they accept a word if it is in the dictionary and is even hinted by the palm?