Update ooo320-m1
[ooovba.git] / sc / source / core / tool / sctictac.cxx
blob563ee6bd66383bdd9e2c607a25db4ac0c530c2fd
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sctictac.cxx,v $
10 * $Revision: 1.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 /* Tic-Tac-Toe program by Steve Chapel schapel@cs.ucsb.edu
35 Uses alpha-beta pruning minimax search to play a "perfect" game.
36 The alpha-beta pruning can be removed, but will increase search time.
37 The heuristic and move ordering in BestMove() can also be removed with
38 an increase in search time. */
40 #include <stdio.h>
41 #include <ctype.h>
44 #include "sctictac.hxx"
46 #ifdef TICTACTOE_SC
47 #include "document.hxx"
48 #include "cell.hxx"
49 #endif
51 const Square_Type ScTicTacToe::Empty = ' ';
52 const Square_Type ScTicTacToe::Human = 'X';
53 const Square_Type ScTicTacToe::Compi = 'O';
54 const int ScTicTacToe::Infinity = 10; /* Higher value than any score */
55 const int ScTicTacToe::Maximum_Moves = ScTicTacToe_Squares; /* Maximum moves in a game */
57 /* Array describing the eight combinations of three squares in a row */
58 const int ScTicTacToe::Three_in_a_Row[ScTicTacToe_Possible_Wins][3] = {
59 { 0, 1, 2 },
60 { 3, 4, 5 },
61 { 6, 7, 8 },
62 { 0, 3, 6 },
63 { 1, 4, 7 },
64 { 2, 5, 8 },
65 { 0, 4, 8 },
66 { 2, 4, 6 }
69 /* Array used in heuristic formula for each move. */
70 const int ScTicTacToe::Heuristic_Array[4][4] = {
71 { 0, -10, -100, -1000 },
72 { 10, 0, 0, 0 },
73 { 100, 0, 0, 0 },
74 { 1000, 0, 0, 0 }
78 #ifdef TICTACTOE_SC
79 ScTicTacToe::ScTicTacToe( ScDocument* pDocP, const ScAddress& rPos ) :
80 aPos( rPos ),
81 pDoc( pDocP ),
82 aStdOut( "Computer plays O, you play X. " ),
83 bInitialized( FALSE )
86 #else
87 ScTicTacToe::ScTicTacToe() :
88 bInitialized( FALSE ),
89 aStdOut( "Computer plays O, you play X. " )
92 #endif
95 /* Return the other player */
96 inline Square_Type ScTicTacToe::Other(Square_Type Player)
98 return Player == Human ? Compi : Human;
102 /* Make a move on the board */
103 inline void ScTicTacToe::Play(int Square, Square_Type Player)
105 Board[Square] = Player;
109 #ifdef TICTACTOE_STDOUT
111 void ScTicTacToe::GetOutput( ByteString& rStr )
113 rStr = aStdOut;
114 aStdOut.Erase();
117 #else // !TICTACTOE_STDOUT
119 void ScTicTacToe::GetOutput( String& rStr )
121 rStr = String( aStdOut, gsl_getSystemTextEncoding() );
122 aStdOut.Erase();
125 #endif // TICTACTOE_STDOUT
128 /* Clear the board */
129 void ScTicTacToe::Initialize( BOOL bHumanFirst )
131 bInitialized = TRUE;
132 aPlayer = (bHumanFirst ? Human : Compi);
133 nMove = 1;
134 for (int i = 0; i < ScTicTacToe_Squares; i++)
135 Board[i] = Empty;
139 /* If a player has won, return the winner. If the game is a tie,
140 return 'C' (for cat). If the game is not over, return Empty. */
141 Square_Type ScTicTacToe::Winner()
143 int i;
144 for (i = 0; i < ScTicTacToe_Possible_Wins; i++)
146 Square_Type Possible_Winner = Board[Three_in_a_Row[i][0]];
147 if (Possible_Winner != Empty &&
148 Possible_Winner == Board[Three_in_a_Row[i][1]] &&
149 Possible_Winner == Board[Three_in_a_Row[i][2]])
150 return Possible_Winner;
153 for (i = 0; i < ScTicTacToe_Squares; i++)
155 if (Board[i] == Empty)
156 return Empty;
159 return 'C';
163 /* Return a heuristic used to determine the order in which the
164 children of a node are searched */
165 int ScTicTacToe::Evaluate(Square_Type Player)
167 int i;
168 int Heuristic = 0;
169 for (i = 0; i < ScTicTacToe_Possible_Wins; i++)
171 int j;
172 int Players = 0, Others = 0;
173 for (j = 0; j < 3; j++)
175 Square_Type Piece = Board[Three_in_a_Row[i][j]];
176 if (Piece == Player)
177 Players++;
178 else if (Piece == Other(Player))
179 Others++;
181 Heuristic += Heuristic_Array[Players][Others];
183 return Heuristic;
187 /* Return the score of the best move found for a board
188 The square to move to is returned in *Square */
189 int ScTicTacToe::BestMove(Square_Type Player, int *Square,
190 int Move_Nbr, int Alpha, int Beta)
192 int Best_Square = -1;
193 int Moves = 0;
194 int i;
195 Move_Heuristic_Type Move_Heuristic[ScTicTacToe_Squares];
197 Total_Nodes++;
199 /* Find the heuristic for each move and sort moves in descending order */
200 for (i = 0; i < ScTicTacToe_Squares; i++)
202 if (Board[i] == Empty)
204 int Heuristic;
205 int j;
206 Play(i, Player);
207 Heuristic = Evaluate(Player);
208 Play(i, Empty);
209 for (j = Moves-1; j >= 0 &&
210 Move_Heuristic[j].Heuristic < Heuristic; j--)
212 Move_Heuristic[j + 1].Heuristic = Move_Heuristic[j].Heuristic;
213 Move_Heuristic[j + 1].Square = Move_Heuristic[j].Square;
215 Move_Heuristic[j + 1].Heuristic = Heuristic;
216 Move_Heuristic[j + 1].Square = i;
217 Moves++;
221 for (i = 0; i < Moves; i++)
223 int Score;
224 int Sq = Move_Heuristic[i].Square;
225 Square_Type W;
227 /* Make a move and get its score */
228 Play(Sq, Player);
230 W = Winner();
231 if (W == Compi)
232 Score = (Maximum_Moves + 1) - Move_Nbr;
233 else if (W == Human)
234 Score = Move_Nbr - (Maximum_Moves + 1);
235 else if (W == 'C')
236 Score = 0;
237 else
238 Score = BestMove(Other(Player), Square, Move_Nbr + 1,
239 Alpha, Beta);
241 Play(Sq, Empty);
243 /* Perform alpha-beta pruning */
244 if (Player == Compi)
246 if (Score >= Beta)
248 *Square = Sq;
249 return Score;
251 else if (Score > Alpha)
253 Alpha = Score;
254 Best_Square = Sq;
257 else
259 if (Score <= Alpha)
261 *Square = Sq;
262 return Score;
264 else if (Score < Beta)
266 Beta = Score;
267 Best_Square = Sq;
271 *Square = Best_Square;
272 if (Player == Compi)
273 return Alpha;
274 else
275 return Beta;
279 /* Provide an English description of the score returned by BestMove */
280 void ScTicTacToe::Describe(int Score)
282 if (Score < 0)
283 aStdOut += "You have a guaranteed win. ";
284 else if (Score == 0)
285 aStdOut += "I can guarantee a tie. ";
286 else
288 aStdOut += "I have a guaranteed win by move ";
289 aStdOut += ByteString::CreateFromInt32( Maximum_Moves - Score + 1 );
290 aStdOut += ". ";
295 /* Have the human or the computer move */
296 void ScTicTacToe::Move( int& Square )
298 if (aPlayer == Compi)
300 Total_Nodes = 0;
301 Describe(BestMove(aPlayer, &Square, nMove, -Infinity, Infinity));
302 aStdOut += ByteString::CreateFromInt32( Total_Nodes );
303 aStdOut += " nodes examined. ";
304 Play(Square, aPlayer);
305 aStdOut += "Move #";
306 aStdOut += ByteString::CreateFromInt32( nMove );
307 aStdOut += " - O moves to ";
308 aStdOut += ByteString::CreateFromInt32( Square + 1 );
309 aStdOut += ". ";
310 aPlayer = Other( aPlayer );
311 nMove++;
313 else
315 if ( Square < 0 || Square >= ScTicTacToe_Squares
316 || Board[Square] != Empty )
317 Square = -1;
318 else
320 Play(Square, aPlayer);
321 aPlayer = Other( aPlayer );
322 nMove++;
328 // Try a move
329 Square_Type ScTicTacToe::TryMove( int& Square )
331 if ( !bInitialized )
332 Initialize( FALSE );
334 Square_Type W = Winner();
335 if ( W == Empty )
337 Move( Square );
338 #ifdef TICTACTOE_STDOUT
339 if ( aStdOut.Len() )
341 puts( aStdOut.GetBuffer() );
342 aStdOut.Erase();
344 #endif
345 W = Winner();
347 if ( W == Empty )
349 if ( aPlayer == Human )
350 PromptHuman();
352 else
354 if (W != 'C')
356 aStdOut += static_cast< char >(W);
357 aStdOut += " wins!";
359 else
360 aStdOut += "It's a tie.";
362 return W;
366 void ScTicTacToe::PromptHuman()
368 aStdOut += "Move #";
369 aStdOut += ByteString::CreateFromInt32( nMove );
370 aStdOut += " - What is X's move?";
374 #ifdef TICTACTOE_SC
376 void ScTicTacToe::DrawPos( int nSquare, const String& rStr )
378 pDoc->SetString( sal::static_int_cast<SCCOL>( aPos.Col()+(nSquare%3) ),
379 sal::static_int_cast<SCROW>( aPos.Row()+(nSquare/3) ), aPos.Tab(), rStr );
383 void ScTicTacToe::DrawBoard()
385 String aStr;
386 for ( USHORT j = 0; j < ScTicTacToe_Squares; j++ )
388 aStr = Board[j];
389 DrawPos( j, aStr );
394 // -1 == Fehler/Redraw, 0 == keine Aenderung, >0 == UserMoveSquare+1
395 int ScTicTacToe::GetStatus()
397 SCCOL nCol;
398 SCROW nRow;
399 SCTAB nTab;
400 nCol = aPos.Col();
401 nRow = aPos.Row();
402 nTab = aPos.Tab();
403 String aStr;
404 int nDiffs = 0;
405 int nSquare = 0;
406 for ( USHORT j = 0; j < ScTicTacToe_Squares; j++ )
408 pDoc->GetString( nCol+(j%3), nRow+(j/3), nTab, aStr );
409 if ( !aStr.Len() )
411 if ( Board[j] != Empty )
412 return -1; // wo was sein muss muss was sein
414 else
416 aStr.ToUpperAscii();
417 if ( aStr.GetChar(0) != Board[j] )
419 if ( Board[j] != Empty )
420 return -1; // bestehendes ueberschrieben
421 // bei erstem Move hat Human angefangen
422 if ( ++nDiffs > 1 )
423 return -1; // mehr als eine Aenderung
424 nSquare = j;
428 if ( nDiffs == 1 )
429 return nSquare + 1;
430 return 0;
434 Square_Type ScTicTacToe::CalcMove()
436 Square_Type W = Winner();
437 int nStat = GetStatus();
438 if ( nStat || (W == Empty && aPlayer == Compi) )
440 if ( nStat == -1 || (nStat > 0 && aPlayer == Compi) )
441 DrawBoard();
442 if ( W == Empty && aPlayer == Human )
444 if ( nStat > 0 )
446 int nSquare = --nStat;
447 W = TryMove( nStat );
448 if ( nStat == -1 )
449 DrawPos( nSquare, String( ' ' ) );
450 else
451 DrawPos( nStat, String( Human ) );
453 else
454 PromptHuman();
456 if ( W == Empty && aPlayer == Compi )
458 W = TryMove( nStat ); // ComputerMove, nStat egal
459 DrawPos( nStat, String( Compi ) );
462 else if ( W == Empty && aPlayer == Human )
463 PromptHuman();
464 return W;
467 #endif // TICTACTOE_SC
470 #ifdef TICTACTOE_STDOUT
471 /* Print the board */
472 void ScTicTacToe::Print()
474 int i;
475 for (i = 0; i < ScTicTacToe_Squares; i += 3)
477 if (i > 0)
478 printf("---+---+---\n");
479 printf(" %c | %c | %c \n", Board[i], Board[i + 1], Board[i + 2]);
481 printf("\n");
485 /* Play a game of tic-tac-toe */
486 void ScTicTacToe::Game()
488 if ( !bInitialized )
489 Initialize( FALSE );
491 int Square = (aPlayer == Compi ? 0 : -1);
492 Square_Type W = Winner();
493 while( W == Empty )
495 Print();
496 W = TryMove( Square );
497 if ( W == Empty )
499 if ( aPlayer == Human )
501 if ( Square != -1 )
502 Print(); // empty board already printed if human moves first
505 puts( aStdOut.GetBuffer() );
506 aStdOut.Erase();
507 scanf("%d", &Square);
508 Square--;
509 W = TryMove( Square );
510 } while ( Square == -1 );
514 Print();
515 puts( aStdOut.GetBuffer() );
516 aStdOut.Erase();
518 #endif // TICTACTOE_STDOUT
521 #ifdef TICTACTOE_MAIN
522 int main()
524 char Answer[80];
526 printf("Welcome to Tic-Tac-Toe!\n\n");
527 printf("Here is the board numbering:\n");
528 printf(" 1 | 2 | 3\n");
529 printf("---+---+---\n");
530 printf(" 4 | 5 | 6\n");
531 printf("---+---+---\n");
532 printf(" 7 | 8 | 9\n");
533 printf("\n");
534 // printf("Computer plays X, you play O.\n");
536 ScTicTacToe aTTT;
537 ByteString aStr;
538 aTTT.GetOutput( aStr );
539 puts( aStr.GetBuffer() );
543 printf("\nDo you want to move first? ");
544 scanf("%s", Answer);
545 aTTT.Initialize( toupper(Answer[0]) == 'Y' );
546 aTTT.Game();
547 printf("\nDo you want to play again? ");
548 scanf("%s", Answer);
549 } while (toupper(Answer[0]) == 'Y');
551 return 0;
553 #endif // TICTACTOE_MAIN