cleaned all trailing white space from source files.
[sdk] / samples / games / scrabble / ScrabbleServer.ec
1 import "scrabble"
2
3 int seed;
4
5 // FOR COMMUNICATION //////////////////////////////////////////
6 struct PlayedTile
7 {
8    int x, y;
9    Letters letter;
10    Letters blankValue;
11
12    void OnSerialize(SerialBuffer buffer)
13    {
14       buffer.Serialize(x);
15       buffer.Serialize(y);
16       buffer.Serialize(letter);
17       buffer.Serialize(blankValue);
18    }
19
20    void OnUnserialize(SerialBuffer buffer)
21    {
22       buffer.Unserialize(x);
23       buffer.Unserialize(y);
24       buffer.Unserialize(letter);
25       buffer.Unserialize(blankValue);
26    }
27 };
28
29 struct PlayedMove
30 {
31    int numTiles;
32    PlayedTile tiles[7];
33    int player;
34    int score;
35
36    void OnSerialize(SerialBuffer buffer)
37    {
38       int c;
39       buffer.Serialize(numTiles);
40       for(c = 0; c<7; c++)
41          buffer.Serialize(tiles[c]);
42       buffer.Serialize(player);
43       buffer.Serialize(score);
44    }
45
46    void OnUnserialize(SerialBuffer buffer)
47    {
48       int c;
49       buffer.Unserialize(numTiles);
50       for(c = 0; c<7; c++)
51          buffer.Unserialize(tiles[c]);
52       buffer.Unserialize(player);
53       buffer.Unserialize(score);
54    }
55 };
56
57 struct PlayerList
58 {
59    char players[4][256];
60    Languages language;
61
62    void OnSerialize(SerialBuffer buffer)
63    {
64       buffer.Serialize(language);
65       buffer.Serialize((StaticString)players[0]);
66       buffer.Serialize((StaticString)players[1]);
67       buffer.Serialize((StaticString)players[2]);
68       buffer.Serialize((StaticString)players[3]);
69    }
70
71    void OnUnserialize(SerialBuffer buffer)
72    {
73       buffer.Unserialize(language);
74       buffer.Unserialize((StaticString)players[0]);
75       buffer.Unserialize((StaticString)players[1]);
76       buffer.Unserialize((StaticString)players[2]);
77       buffer.Unserialize((StaticString)players[3]);
78    }
79 };
80
81 //////////////////////////////////////////
82
83 class Player
84 {
85    Letters letters[7];
86    int numLetters;
87    int totalScore;
88    char * name;
89
90    int id;
91    ServerConnection connection;
92
93    ~Player()
94    {
95       delete name;
96    }
97 };
98
99 static char * dicos[Languages] = { ":english.txt", ":dico.txt" };
100
101 class ScrabbleGame
102 {
103    int lettersAvailable[Letters];
104    int numLettersAvailable;
105    AVLTree<String> dictionary { };
106    int curPlayer;
107    Player players[MaxPlayers];
108    Languages language;
109
110    property Languages language
111    {
112       set
113       {
114          language = value;
115          LoadWords(dicos[value]);
116       }
117    }
118
119    Letters board[15][15];
120    Letters blankValues[15][15];
121    PlayedMove curMove;
122    bool gameStarted;
123
124    ~ScrabbleGame()
125    {
126       int c;
127       dictionary.Free();
128       for(c = 0; c<MaxPlayers; c++)
129          delete players[c];
130    }
131
132    ScrabbleGame()
133    {
134
135    }
136
137    void GetTiles(int tilesPlayer, PlayedMove move)
138    {
139       Player player = players[tilesPlayer];
140       int c;
141       move.numTiles = 0;
142
143       while(player.numLetters < 7 && numLettersAvailable)
144       {
145          Letters letter;
146          int r = (Letters)GetRandom(0, numLettersAvailable-1);
147          int a = 0;
148
149          for(letter = 0; letter<Letters::empty; letter++)
150          {
151             a += lettersAvailable[letter];
152             if(a > r)
153                break;
154          }
155          numLettersAvailable--;
156          lettersAvailable[letter]--;
157
158          player.letters[player.numLetters] = letter;
159          player.numLetters++;
160
161          move.tiles[move.numTiles++].letter = letter;
162       }
163    }
164
165    void NewGame()
166    {
167       int c;
168       int numPlayers = 0;
169
170       for(c = 0; c<MaxPlayers; c++)
171          if(players[c])
172             numPlayers++;
173
174       if(numPlayers > 0)
175       {
176          int x,y;
177          Letters l;
178          PlayerList list { };
179          PlayedMove tiles { };
180
181          numLettersAvailable = 0;
182
183          for(l = 0; l<Letters::empty; l++)
184          {
185             numLettersAvailable += lettersCount[language][l];
186             lettersAvailable[l] = lettersCount[language][l];
187          }
188
189          seed = (uint)(GetTime() * 1000);
190          //seed = 256131322;
191          RandomSeed(seed);
192          //Logf("Seeded with %d\n", seed);
193
194          for(y = 0; y<15; y++)
195             for(x = 0; x<15; x++)
196                board[y][x] = blankValues[y][x] = empty;
197
198
199          for(c = 0; c<MaxPlayers; c++)
200             if(players[c])
201             {
202                curPlayer = c;
203                break;
204             }
205
206          gameStarted = true;
207
208          strcpy(list.players[0], scrabbleGame.players[0] ? scrabbleGame.players[0].name : "");
209          strcpy(list.players[1], scrabbleGame.players[1] ? scrabbleGame.players[1].name : "");
210          strcpy(list.players[2], scrabbleGame.players[2] ? scrabbleGame.players[2].name : "");
211          strcpy(list.players[3], scrabbleGame.players[3] ? scrabbleGame.players[3].name : "");
212          list.language = scrabbleGame.language;
213
214          for(c = 0; c<MaxPlayers; c++)
215             if(players[c])
216             {
217                scrabbleGame.GetTiles(c, tiles);
218                scrabbleGame.players[c].connection.GameStarted(list, tiles);
219             }
220       }
221    }
222
223    void LoadWords(char * fileName)
224    {
225       File f = FileOpen(fileName, read);
226       if(f)
227       {
228          dictionary.Free();
229          while(!f.Eof())
230          {
231             char word[100];
232             f.GetLine(word, sizeof(word));
233             dictionary.Add(CopyString(word));
234          }
235          delete f;
236       }
237
238       /*{
239          IteratorPointer test1, test2;
240          test1 = dictionary.Find("gewurztraminer");
241          test2 = dictionary.Find("gewurstraminer");
242          Print("");
243       }*/
244
245    }
246
247    bool CheckWord(Letters newBoard[15][15], Direction direction, int where, int start, int end, int * score)
248    {
249       char word[16];
250       int c, len = 0;
251       bool found;
252       int wordScore = 0;
253       int wordMultiplier = 1;
254
255       for(c = start; c<= end; c++)
256       {
257          int y = direction ? c : where;
258          int x = direction ? where : c;
259          Letters letter = newBoard[y][x];
260          int multiplier = 1;
261
262          if(board[y][x] == empty)
263          {
264             if(squareValues[y][x] == doubleLetter) multiplier = 2;
265             else if(squareValues[y][x] == tripleLetter) multiplier = 3;
266          }
267
268          wordScore += lettersValue[language][letter] * multiplier;
269
270          if(board[y][x] == empty)
271          {
272             if(squareValues[y][x] == doubleWord) wordMultiplier *= 2;
273             else if(squareValues[y][x] == tripleWord) wordMultiplier *= 3;
274          }
275
276          if(letter == blank)
277             letter = blankValues[y][x];
278          word[len++] = (char)letter + 'a';
279       }
280       word[len] = 0;
281       found = dictionary.Find(word) != null;
282       Logf("%s: %s\n", word, found ? "found :)" : "not found :(");
283
284       *score += wordScore * wordMultiplier;
285       return found;
286    }
287
288    bool VerifyMove(Letters newBoard[15][15], int * score)
289    {
290       int x, y;
291       int c;
292       int numLetters = 0;
293       Direction direction = horizontal;
294
295       int wordX;
296       int wordY;
297       int firstX = MAXINT, lastX = MININT;
298       int firstY = MAXINT, lastY = MININT;
299       int first, last, where;
300       int wordStart, wordEnd;
301       bool anchored = false;
302
303       *score = 0;
304
305       for(y = 0; y<15; y++)
306       {
307          for(x = 0; x<15; x++)
308          {
309             if(board[y][x] == empty && newBoard[y][x] != empty)
310             {
311                wordX = x;
312                wordY = y;
313                if(x < firstX) firstX = x;
314                if(y < firstY) firstY = y;
315                if(x > lastX) lastX = x;
316                if(y > lastY) lastY = y;
317                numLetters++;
318             }
319          }
320       }
321       if(!numLetters) return false;
322       if(lastY - firstY > 0)
323       {
324          if(lastX - firstX > 1) return false;
325          direction = vertical;
326       }
327       else if(lastX - firstX == 0)
328       {
329          if(((firstY > 0 && newBoard[firstY-1][firstX] != empty) ||
330             (firstY < 14 && newBoard[firstY+1][firstX] != empty)) &&
331             ((firstX == 0 || newBoard[firstY][firstX-1] == empty) &&
332             (firstX == 14 || newBoard[firstY][firstX+1] == empty)))
333             direction = vertical;
334       }
335
336       first = direction ? firstY : firstX;
337       last = direction ? lastY : lastX;
338
339       where = direction ? firstX : firstY;
340
341       for(c = first; c <= last; c++)
342       {
343          Letters letter = direction ? newBoard[c][where] : newBoard[where][c];
344          if(letter == empty) return false;
345       }
346
347       for(c = first; c>=0; c--)
348       {
349          Letters letter = direction ? newBoard[c][where] : newBoard[where][c];
350          if(letter == empty) break;
351          wordStart = c;
352          if(c != first)
353             anchored = true;
354       }
355       for(c = last; c<15; c++)
356       {
357          Letters letter = direction ? newBoard[c][where] : newBoard[where][c];
358          if(letter == empty) break;
359          wordEnd = c;
360          if(c != last)
361             anchored = true;
362       }
363       if(!CheckWord(newBoard, direction, where, wordStart, wordEnd, score))
364          return false;
365
366       for(c = first; c <= last; c++)
367       {
368          if((direction ? board[c][where] : board[where][c]) == empty)
369          {
370             int wordStart, wordEnd;
371             int a;
372
373             for(a = where; a>=0; a--)
374             {
375                Letters letter = direction ? newBoard[c][a] : newBoard[a][c];
376                if(letter == empty) break;
377                wordStart = a;
378                if(a != where)
379                   anchored = true;
380             }
381             for(a = where; a<15; a++)
382             {
383                Letters letter = direction ? newBoard[c][a] : newBoard[a][c];
384                if(letter == empty) break;
385                wordEnd = a;
386                if(a != where)
387                   anchored = true;
388             }
389             if(wordEnd > wordStart)
390                if(!CheckWord(newBoard, !direction, c, wordStart, wordEnd, score))
391                   return false;
392          }
393          else
394             anchored = true;
395       }
396       if(newBoard[7][7] != empty && board[7][7] == empty) anchored = true;
397       if(!anchored) return false;
398       if(numLetters == 7) *score += 50;
399       return true;
400    }
401
402    void EndGame()
403    {
404       if(gameStarted)
405       {
406          int c;
407          for(c = 0; c<MaxPlayers; c++)
408          {
409             delete scrabbleGame.players[c];
410          }
411          gameStarted = false;
412       }
413    }
414 }
415
416 ScrabbleGame scrabbleGame;
417
418 remote class ServerConnection
419 {
420 public:
421    // Remote Functions
422    Player player;
423
424    ~ServerConnection()
425    {
426       if(player)
427       {
428          //scrabbleGame.players[player.id] = null;
429          delete scrabbleGame.players[player.id];
430          delete player;
431          scrabbleGame.EndGame();
432       }
433    }
434
435    int Join()
436    {
437       int result = -1;
438       if(!scrabbleGame.gameStarted)
439       {
440          int c;
441          for(c = 0; c<MaxPlayers; c++)
442          {
443             if(!scrabbleGame.players[c])
444                break;
445          }
446          if(c < MaxPlayers)
447          {
448             player = scrabbleGame.players[c] = Player { id = c };
449             player.connection = this;
450             incref player;
451             incref scrabbleGame.players[c];
452             result = c;
453          }
454       }
455       return result;
456    }
457
458    bool SetName(const String name)
459    {
460       if(player)
461       {
462          player.name = CopyString(name);
463          if(!scrabble.scoreFields[player.id])
464          {
465             scrabble.scoreFields[player.id] = DataField { dataType = class(int), header = name, width = 40 };
466             //incref scrabble.scoreFields[player.id];
467             scrabble.scores.AddField(scrabble.scoreFields[player.id]);
468          }
469          scrabble.scoreFields[player.id].header = name;
470       }
471       return true;
472    }
473
474    bool PlayTiles(PlayedMove move)
475    {
476       if(player && scrabbleGame.players[scrabbleGame.curPlayer] == player)
477       {
478          Letters newBoard[15][15];
479          int c;
480          int score;
481
482          memcpy(newBoard, scrabbleGame.board, 15*15*sizeof(Letters));
483          for(c = 0; c<move.numTiles; c++)
484          {
485             if(newBoard[move.tiles[c].y][move.tiles[c].x] == empty)
486             {
487                newBoard[move.tiles[c].y][move.tiles[c].x] = move.tiles[c].letter;
488                scrabbleGame.blankValues[move.tiles[c].y][move.tiles[c].x] = move.tiles[c].blankValue;
489             }
490             else
491                return false;
492          }
493          if(scrabbleGame.VerifyMove(newBoard, &score))
494          {
495             for(c = 0; c<move.numTiles; c++)
496             {
497                int d;
498                bool found = false;
499                for(d = 0; d<player.numLetters; d++)
500                   if(player.letters[d] == move.tiles[c].letter)
501                   {
502                      memmove(player.letters + d, player.letters + d + 1, sizeof(int) * (player.numLetters - d - 1));
503                      player.numLetters--;
504                      found = true;
505                      break;
506                   }
507                if(!found)
508                {
509                   Logf("Letter not found!\n");
510                   return false;
511                }
512             }
513
514             player.totalScore += score;
515             memcpy(scrabbleGame.board, newBoard, 15*15*sizeof(Letters));
516
517             scrabbleGame.curMove = move;
518             scrabbleGame.curMove.player = scrabbleGame.curPlayer;
519             scrabbleGame.curMove.score = score;
520
521             // Return Tiles
522             scrabbleGame.GetTiles(scrabbleGame.curPlayer, move);
523
524             for(c = 0; c<MaxPlayers; c++)
525                if(scrabbleGame.players[c])
526                   scrabbleGame.players[c].connection.MovePlayed(scrabbleGame.curMove);
527
528             do { if(++scrabbleGame.curPlayer == MaxPlayers) scrabbleGame.curPlayer = 0; } while(!scrabbleGame.players[scrabbleGame.curPlayer]);
529             return true;
530          }
531       }
532       return false;
533    }
534
535    bool DiscardTiles(PlayedMove move)
536    {
537       if(player && scrabbleGame.numLettersAvailable >= move.numTiles && scrabbleGame.players[scrabbleGame.curPlayer] == player)
538       {
539          int c;
540          PlayedMove newTiles { };
541
542          for(c = 0; c<move.numTiles; c++)
543          {
544             int d;
545             for(d = 0; d<player.numLetters; d++)
546                if(player.letters[d] == move.tiles[c].letter)
547                {
548                   memmove(player.letters + d, player.letters + d + 1, sizeof(int) * (player.numLetters - d - 1));
549                   player.numLetters--;
550                   break;
551                }
552          }
553
554          scrabbleGame.GetTiles(scrabbleGame.curPlayer, newTiles);
555
556          for(c = 0; c<move.numTiles; c++)
557          {
558             scrabbleGame.lettersAvailable[move.tiles[c].letter]++;
559             scrabbleGame.numLettersAvailable++;
560          }
561
562          scrabbleGame.curMove = { }; // TODO: Add informing other players of number of exchanged letters when passing...
563          scrabbleGame.curMove.player = scrabbleGame.curPlayer;
564
565          move = newTiles;
566
567          for(c = 0; c<MaxPlayers; c++)
568             if(scrabbleGame.players[c])
569                scrabbleGame.players[c].connection.MovePlayed(scrabbleGame.curMove);
570
571          do { if(++scrabbleGame.curPlayer == MaxPlayers) scrabbleGame.curPlayer = 0; } while(!scrabbleGame.players[scrabbleGame.curPlayer]);
572
573          return true;
574       }
575       return false;
576    }
577
578    virtual void MovePlayed(PlayedMove move);
579    virtual void GameStarted(PlayerList list, PlayedMove tiles);
580 }