井字棋小游戏(C语言)

2019/10/06 14:57
阅读数 181

最近沉迷于《NetHack》、《DCSS》等字符界面游戏,对其很感兴趣,于是用C语言写了个字符界面的井字棋小游戏,作为练手。代码写得不好。欢迎大家指教。

编写时遇到了一些问题,我原先准备用循环,直到读取到正确的输入。可该死的getchar函数,在读取后,又把回车又传给下次循环,我不得不对其进行处理。

设定井字棋的AI时,有个有趣的地方就是,先下四个角比先下中心优势更大,这违背了我以前的直觉。

  1 #include <stdio.h>
  2 #include <ctype.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5 #include <time.h>
  6 
  7 void drawBoard(char *board) //绘制棋盘
  8 {
  9     printf("%c|%c|%c\n", board[7], board[8], board[9]);
 10     puts("-+-+-");
 11     printf("%c|%c|%c\n", board[4], board[5], board[6]);
 12     puts("-+-+-");
 13     printf("%c|%c|%c\n", board[1], board[2], board[3]);
 14     puts("-+-+-");
 15 }
 16 
 17 char inputPlayerLetter() //玩家选择棋子
 18 {
 19     char letter;
 20     puts("你想用X还是O?");
 21     do{
 22         letter = toupper(getchar());
 23         if (letter == '\n')
 24             continue;
 25         if (letter != 'X' && letter != 'O')
 26             puts("你想用X还是O?");
 27     }while (letter != 'X' && letter != 'O');
 28     
 29     return letter;
 30 
 31 }
 32 
 33 void makeMove(char *board,char letter,int move) //落子
 34 {
 35     board[move] = letter;
 36 }
 37 
 38 _Bool isWinner(char *bo, char le) //判定是否获胜
 39 {
 40     return ((bo[7] == le && bo[8] == le && bo[9] == le) ||
 41         (bo[4] == le && bo[5] == le && bo[6] == le) ||
 42         (bo[1] == le && bo[2] == le && bo[3] == le) ||
 43         (bo[7] == le && bo[4] == le && bo[1] == le) ||
 44         (bo[8] == le && bo[5] == le && bo[2] == le) ||
 45         (bo[9] == le && bo[6] == le && bo[3] == le) ||
 46         (bo[7] == le && bo[5] == le && bo[3] == le) ||
 47         (bo[9] == le && bo[5] == le && bo[1] == le));
 48 }
 49 
 50 const char getBoardCopy(char *board) //复制棋盘,让电脑预判可能出现的情况
 51 {
 52     char boardCopy[10];
 53     for (int i = 1; i < 10; i++)
 54         boardCopy[i] = board[i];
 55     return *boardCopy;
 56 }
 57 
 58 _Bool isSpaceFree(char *board,int move) //判断棋盘上是否为空
 59 {
 60     return board[move] == ' ';
 61 }
 62 
 63 int getPlayerMove(char *board) //读取玩家棋子移动
 64 {
 65     puts("你下一步走哪里?(1-9)");
 66     int move;
 67     do {
 68         move = getchar() - '0';
 69         if (move == '\n' - '0')
 70             continue;
 71         if (move < 1 || move > 9 || !isSpaceFree(board, move))
 72             puts("你下一步走哪里?(1-9)");
 73     }while (move < 1 || move > 9 || !isSpaceFree(board, move));
 74     return move;
 75 }
 76 
 77 int chooseRandomMoveFromList(char *board,char *movelist, int n) //随机读取计算机可移动的位置
 78 {
 79     int possibleMove[4]; //每轮选择最多只有四个
 80     int j = 0;
 81     for (int i = 0; i < n; i++)
 82         if (isSpaceFree(board, movelist[i] - '0'))
 83             possibleMove[j++] = movelist[i] - '0';
 84 
 85     if (j != 0)
 86         return possibleMove[rand()%j];
 87     else
 88         return 0;
 89 }
 90 
 91 int getComputerMove(char board[], char computerLetter) //获得计算机的移动
 92 {
 93     char playerLetter;
 94     char boardCopy[10];
 95     if (computerLetter == 'X') //根据计算机的棋子,判断玩家棋子
 96         playerLetter = 'O';
 97     else
 98         playerLetter = 'X';
 99 
100     for (int i = 1; i < 10; i++){ //如果下一步可获胜,下那一步
101         strcpy(boardCopy, board);
102         if (isSpaceFree(boardCopy, i)) {
103             makeMove(boardCopy, computerLetter,i);
104                 if (isWinner(boardCopy, computerLetter))
105                     return i;
106         }
107     }
108 
109     for (int i = 1; i < 10; i++){ //如果下一步玩家会获胜,占那个位置
110         strcpy(boardCopy,board);
111         if (isSpaceFree(boardCopy, i)) {
112             makeMove(boardCopy, playerLetter,i);
113                 if (isWinner(boardCopy, playerLetter))
114                     return i;
115         }
116     }
117 
118     int move; //如果下一步不是决胜步
119     move = chooseRandomMoveFromList(board, "1379", 4); //四个角优先
120     if (move != 0)
121         return move;
122 
123     move = chooseRandomMoveFromList(board, "5", 1); //中间
124     if (move != 0)
125         return move;
126     
127     return chooseRandomMoveFromList(board, "2468", 4); //剩下的位置
128 }
129 
130 _Bool isBoardFull(char *board) //判断棋盘是否满了
131 {
132     for (int i = 1; i < 10; i++)
133         if (isSpaceFree(board, i))
134             return 0;
135     return 1;
136 }
137 
138 _Bool isAgain() //再来一局
139 {
140     char again;
141     do{
142         again = tolower(getchar());
143         if (again == '\n')
144             continue;
145         if (again != 'n' && again != 'y')
146             puts("请输入y或n。");
147     }while (again != 'n' && again != 'y');
148     
149     if (again == 'y')
150         return 1;
151     else 
152         return 0;
153 }
154 
155 
156 int main()
157 {
158     puts("欢迎来玩井字棋!") ;
159 
160     while(1) { //游戏
161         char theBoard[10];
162         for (int i = 1; i < 10; i++) //将棋盘设为空白
163             theBoard[i] = ' ';
164         char playerLetter = inputPlayerLetter(); //获得玩家所选的棋子
165         char computerLetter = (playerLetter == 'X')?'O': 'X' ;
166         //获得计算机的棋子
167         _Bool isTurnPlayer; //设定是否是玩家回合
168         int move;
169         srand((unsigned)time(NULL)); //随机先后手
170         if (rand() % 2) {
171             isTurnPlayer = 0;
172             puts("电脑先走。");
173         }else {
174                    isTurnPlayer = 1;
175             puts("玩家先走。");
176         }
177         _Bool gameIsPlaying = 1; //设定游戏是否进行
178 
179         while (gameIsPlaying) {
180 
181             if (isTurnPlayer) { //如果是玩家回合
182                 drawBoard(theBoard);
183                 move = getPlayerMove(theBoard);
184                 makeMove(theBoard, playerLetter, move);
185 
186                 if (isWinner(theBoard, playerLetter)) { //如果获胜
187                     drawBoard(theBoard);
188                     puts("太棒了!你获胜了!");
189                     gameIsPlaying = 0;
190                 }
191             
192                 else { //如果平局
193                     if (isBoardFull(theBoard)) {
194                         drawBoard(theBoard);
195                         puts("平局了!");
196                         break;
197                     }
198                     else //设定轮到计算机
199                         isTurnPlayer = 0;
200                 }
201             }
202 
203             else { //轮到计算机了
204                 move = getComputerMove(theBoard, computerLetter);
205                 makeMove(theBoard, computerLetter, move);
206                 if (isWinner(theBoard, computerLetter)) { //如果获胜
207                     drawBoard(theBoard);
208                     puts("电脑打败了你!你输了。");
209                     gameIsPlaying = 0;
210                 } else { //平局
211                     if (isBoardFull(theBoard)) {
212                         drawBoard(theBoard);
213                         puts("平局了!");
214                         break;
215                     } else // 设定轮到玩家
216                         isTurnPlayer = 1;
217                 }
218             }
219         }
220         puts("再来一局?(yes或no)");
221         if (!isAgain())
222             break;
223     }
224     return 0;
225 }

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部