基于STM32五子棋游戲

      網(wǎng)友投稿 727 2022-05-28

      基于STM32的五子棋小游戲

      前言

      項目要求

      項目總體設(shè)計

      軟件實現(xiàn)

      重要繪制圖形函數(shù)介紹

      繪制按鈕函數(shù)

      繪制棋子函數(shù)

      繪制棋盤界面函數(shù)

      重要界面函數(shù)介紹

      模式選擇界面

      對戰(zhàn)界面

      設(shè)置界面

      關(guān)于界面

      重要屏幕測試相關(guān)函數(shù)

      單人對戰(zhàn)下棋函數(shù)

      有一方勝利后調(diào)用函數(shù)

      總結(jié)

      實際效果視頻鏈接

      前言

      之前寫過一篇文章是關(guān)于C語言實現(xiàn)五子棋,知道了實現(xiàn)五子棋的基本原理。本來打算很快的把五子棋移植到STM32F103精英版上,但是前幾周實驗室納新、期中考試、開放實驗各種事情導(dǎo)致一直沒有重大進展。在忙完以后終于在這個周完成了五子棋的全部功能。在調(diào)試的過程中總是會出現(xiàn)各種問題,然后去尋找問題、解決問題。這也是第一次一個人獨自做一個比較完備的具體項目,通過項目學(xué)到了很多知識以及知道如何具有一個系統(tǒng)的思維來完成這樣一個項目。

      項目要求

      基礎(chǔ)要求:實現(xiàn)下棋并判斷輸贏和基本的游戲介紹

      高級要求:界面美觀、可以選擇人機模式、雙人對戰(zhàn)模式、智能提示落子點、悔棋以及一些簡單設(shè)置。

      項目總體設(shè)計

      通過定義一個16*16的數(shù)組g_Chess[16][16]和一個記錄棋子數(shù)量的變量g_ChessNum。初始化棋子總數(shù)為0且每點都沒有棋子,則初始化數(shù)組全部為0。每當(dāng)檢測到有棋子落下時棋子總數(shù)加一,而該點的坐標(biāo)所對應(yīng)的數(shù)組的值為下該棋子時棋子的總數(shù)。

      模式選擇:定義一個變量g_Mode,初始化g_Mode=0。如果

      g_Mode=1則是人機模式

      ,如果

      g_Mode=2則是雙人對戰(zhàn)模式

      下棋:判斷該點坐標(biāo)對應(yīng)的數(shù)組的值是否為0,如果是0則可以下棋,如果不是0則返回重新判斷。如果是人機模式,則在觸摸屏沒有按下時進行計算相關(guān)棋子坐標(biāo)。每下一顆棋子后判斷是否連成5顆棋子。如果連接成5顆棋子

      判斷白棋或者黑棋:通過

      棋子總數(shù)對2求余

      來判斷該點是黑棋還是白棋。

      悔棋:讓該點坐標(biāo)對應(yīng)的

      數(shù)組值等于0棋子總數(shù)減1

      ,清除該棋子。如果是人機對戰(zhàn),則清理最后下的兩顆棋子,棋子總數(shù)減二。

      重新開始:讓

      數(shù)組的值都為0

      以及

      棋子總數(shù)等于0

      ,重新畫界面

      返回:返回主界面選擇模式。

      軟件實現(xiàn)

      重要繪制圖形函數(shù)介紹

      繪制按鈕函數(shù)

      void DrawButton(int x, int y, int width, int height, u8* Text, char sta) { int iLen = strlen((char*)Text); if (x > 239 || x < 0 || y < 0 || y > 319) return; POINT_COLOR = WHITE; LCD_DrawRectangle(x, y, x+width, y+height); if (sta==1) { LCD_Fill(x+1, y+1, x+width-1, y+height-1, BLUE); BACK_COLOR = BLUE; Show_Str(x+((width-iLen*8)/2), y+((height-16)/2), 200, 16, Text, 16, 0); } else if(sta==0) { LCD_Fill(x+1, y+1, x+width-1, y+height-1, GRAY); BACK_COLOR = GRAY; Show_Str(x+((width-iLen*8)/2)+2, y+((height-16)/2)+2, 200, 16, Text, 16, 0); } else if(sta==2) { LCD_Fill(x+1, y+1, x+width-1, y+height-1, GREEN ); BACK_COLOR = GREEN ; Show_Str(x+((width-iLen*8)/2)+2, y+((height-16)/2)+2, 200, 16, Text, 16, 0); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      可以通過調(diào)用該函數(shù)來實現(xiàn)畫按鈕,通過改變參數(shù)sta的值來改變按鈕的背景顏色

      繪制棋子函數(shù)

      void DrawChess(int x, int y, int num, char sta) { uint16_t ChessColor; uint16_t xChess; uint16_t yChess; if (x>15 || x<0 || y>15 || y<0)return; //超范圍了 //判斷是下棋還是復(fù)盤 if (sta) { if (g_Chess[x][y]!=0)return; //已有棋子 } //判斷棋子顏色 (num%2==0) ? (ChessColor=BLACK) : (ChessColor=WHITE); //計算棋子坐標(biāo) xChess = CHESSBOARD_START_X + (x*CHESSGRID_SIZE); yChess = CHESSBOARD_START_Y + (y*CHESSGRID_SIZE); LcdDrawCircleA(xChess, yChess, CHESSGRID_SIZE/2-1, ChessColor, 1); if(voice==1) //判斷燈光是否打開 若打開 每次下子蜂鳴器響100ms { LED0=0; delay_ms(100); LED0=1; } delay_ms(10); if (sta == 0) return; g_ChessNum++; g_Chess[x][y] = g_ChessNum; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      每畫一個棋子棋子數(shù)量加一,在判斷畫棋子前判斷是否可以下棋,同時判斷燈光是否打開。如果可以下棋且燈光打開每下一顆棋LE0閃爍100ms。

      繪制棋盤界面函數(shù)

      void DrawChessBoard(void) { int i; //填充棋盤背景色 LCD_Fill(CHESSBOARD_START_X-5, CHESSBOARD_START_Y-5, CHESSBOARD_END_X+5, CHESSBOARD_END_Y+5, CHESSBOARD_COLOR); POINT_COLOR = BLACK; //繪制邊框線 LCD_DrawRectangle(CHESSBOARD_START_X-3, CHESSBOARD_START_Y-3, CHESSBOARD_END_X+3, CHESSBOARD_END_Y+3); LCD_DrawRectangle(CHESSBOARD_START_X-4, CHESSBOARD_START_Y-4, CHESSBOARD_END_X+4, CHESSBOARD_END_Y+4); LCD_DrawRectangle(CHESSBOARD_START_X, CHESSBOARD_START_Y, CHESSBOARD_END_X, CHESSBOARD_END_Y); POINT_COLOR = BLACK; //繪制垂直線 for (i = 1; i < 15; i++) { LCD_DrawLine(CHESSBOARD_START_X, CHESSBOARD_START_Y + (CHESSGRID_SIZE*i), CHESSBOARD_END_X, CHESSBOARD_START_Y + (CHESSGRID_SIZE*i)); } //繪制水平線 for (i = 1; i < 15; i++) { LCD_DrawLine(CHESSBOARD_START_X + (CHESSGRID_SIZE*i), CHESSBOARD_START_Y, CHESSBOARD_START_X + (CHESSGRID_SIZE*i), CHESSBOARD_END_Y); } DrawButton(5, 285, 80, 25, (u8*)"重新開始", 1); DrawButton(87, 285, 48, 25, (u8*)"悔棋", 1); DrawButton(137, 285, 48, 25, (u8*)"幫助", 1); DrawButton(187, 285, 49, 25, (u8*)"返回", 1); }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      重要界面函數(shù)介紹

      模式選擇界面

      void Main(void)//主界面函數(shù) { LCD_Clear(GBLUE); BACK_COLOR = GBLUE; POINT_COLOR = RED; Show_Str((240 - 24*3)/2, 30, 200, 24, (u8*)"五子棋", 24, 0); //創(chuàng)建按鈕 DrawButton(40, 100, 160, 40, (u8*)"人機對戰(zhàn)", 1); DrawButton(40, 150, 160, 40, (u8*)"雙人對戰(zhàn)", 1); DrawButton(40, 200, 160, 40, (u8*)"游戲介紹", 1); DrawButton(40, 250, 160, 40, (u8*)"設(shè)置", 1); }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      對戰(zhàn)界面

      void One(void) { LCD_Clear(BRRED); POINT_COLOR = WHITE; DrawChessBoard(); BACK_COLOR = BRRED; POINT_COLOR=BLACK; Show_Str(34, 10, 240, 34, (u8*)"五子棋人機對戰(zhàn)", 24, 0); One_test(); }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      設(shè)置界面

      void Setting(void) { POINT_COLOR = WHITE; //繪制關(guān)于窗口 LCD_DrawRectangle(20, 110, 220, 220); LCD_DrawRectangle(21, 111, 219, 219); LCD_Fill(22, 112, 218, 218, BLACK); BACK_COLOR = BLACK; Show_Str(104, 115, 32, 16, (u8*)"設(shè)置", 16, 0); Show_Str(40, 140, 136, 16, (u8*)"燈光", 16, 0); Show_Str(40, 165, 136, 16, (u8*)"關(guān)于", 16, 0); //繪制按鈕 DrawButton(150, 140, 25, 20, (u8*)"開", 2); DrawButton(175, 140, 25, 20, (u8*)"關(guān)", 0); DrawButton(150, 165, 50, 20, (u8*)"打開", 2); DrawButton(90, 195, 60, 20, (u8*)"返回", 1); Set_test(); }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      關(guān)于界面

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      重要屏幕測試相關(guān)函數(shù)

      屏幕測試模塊原理基本差別不大,主要是位置的差別。博主在這里主要介紹單人對戰(zhàn)時的屏幕測試函數(shù)

      單人對戰(zhàn)下棋函數(shù)

      void One_test(void)//雙人對戰(zhàn)屏幕掃描 { u16 x, y; static int xChess = 0; static int yChess = 0; // static int xPre = 0; // static int yPre = 0; static uint8_t State = 0; //判斷觸摸屏是否被按下 if (tp_dev.sta&TP_PRES_DOWN) { while(1) { tp_dev.scan(0); x = tp_dev.x[0]; y = tp_dev.y[0]; if(tp_dev.sta&TP_PRES_DOWN) //觸摸屏被按下 { if(tp_dev.x[0]CHESSBOARD_START_X &&tp_dev.y[0]>CHESSBOARD_START_Y) { if(((x - CHESSBOARD_START_X )%CHESSGRID_SIZE)<=7) xChess = (x - CHESSBOARD_START_X ) / CHESSGRID_SIZE; else xChess = ((x - CHESSBOARD_START_X ) / CHESSGRID_SIZE)+1; if((yChess = (y - CHESSBOARD_START_Y ) % CHESSGRID_SIZE)<7) yChess = (y - CHESSBOARD_START_Y ) / CHESSGRID_SIZE; else yChess = (y - CHESSBOARD_START_Y ) / CHESSGRID_SIZE+1; // if (g_ChessNum%2)delay_ms(300); if((g_ChessNum%2)==0) DrawChess(xChess, yChess, g_ChessNum, 1); State = GameOver(xChess, yChess); if(State==1||State==2) { POINT_COLOR = WHITE; LCD_DrawRectangle(18, 138, 222, 178); LCD_DrawRectangle(19, 139, 221, 177); LCD_Fill(20, 140, 220, 176, BLACK); BACK_COLOR = BLACK; switch(State) { case 1: Show_Str(20 + (200 - 16*2)/2, 150, 200, 16, (u8*)"和棋", 16, 0); break; case 2: if (g_Mode == 1) { if (g_ChessNum % 2) { POINT_COLOR=RED; Show_Str((240 - 16*4)/2, 150, 200, 16, (u8*)"你贏啦!!", 16, 0); } else { Show_Str((240 - 16*3)/2, 150, 200, 16, (u8*)"很遺憾 你輸了", 16, 0); } } delay_ms(1000);//延時提示1秒 Recover(); Over_test(); break; } } } } else { if (x > 5 && x < 85 && y > 285 && y < 310)//重新開始 ResStart(); if (x > 87 && x < 135 && y > 285 && y < 310)//悔棋 { if(g_Mode==1) RetractChess(); } if(x > 137 && x < 185 && y > 285 && y < 310) { //計算AI下子坐標(biāo) GetAIPoint(&xChess, &yChess); delay_ms(10); CHESS_Blink(xChess,yChess); } if (x > 187 && x < 236 && y > 285 && y < 310)//返回 { ResStart(); GameInit(); } } } else { if(!State) { if ((g_ChessNum>0)&&(g_ChessNum%2==1)) { //計算AI下子坐標(biāo) GetAIPoint(&xChess, &yChess); if((g_ChessNum%2==1)) DrawChess(xChess, yChess, g_ChessNum, 1); State = GameOver(xChess, yChess); if(State==1||State==2) { POINT_COLOR = WHITE; LCD_DrawRectangle(18, 138, 222, 178); LCD_DrawRectangle(19, 139, 221, 177); LCD_Fill(20, 140, 220, 176, BLACK); BACK_COLOR = BLACK; switch(State) { case 1: Show_Str(20 + (200 - 16*2)/2, 150, 200, 16, (u8*)"和棋", 16, 0); break; case 2: if (g_Mode == 1) { if (g_ChessNum % 2) { POINT_COLOR=RED; Show_Str((240 - 16*4)/2, 150, 200, 16, (u8*)"你贏啦!!", 16, 0); } else { Show_Str((240 - 16*3)/2, 150, 200, 16, (u8*)"很遺憾 你輸了", 16, 0); } } delay_ms(1000);//延時提示1秒 Recover(); Over_test(); break; } } } } else { t++; if(t==10) { t=0; } } } } }else delay_ms(10); //沒有按鍵按下的時候 }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      基于STM32的五子棋游戲

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      102

      103

      104

      105

      106

      107

      108

      109

      110

      111

      112

      113

      114

      115

      116

      117

      118

      119

      120

      121

      122

      123

      124

      125

      126

      127

      128

      129

      130

      131

      132

      133

      134

      135

      136

      137

      138

      139

      140

      141

      142

      143

      144

      145

      146

      147

      這個函數(shù)大致分為兩部分,第一部分在棋盤范圍內(nèi),主要負(fù)責(zé)下棋還有判斷是否連接成5顆棋子。第二部分主要是在下方按鈕范圍內(nèi)檢測并調(diào)用相關(guān)函數(shù)。同時在屏幕沒有按下時來改變t的值來產(chǎn)生偽隨機數(shù)。從而為AI下棋提供偽隨機數(shù)。同時在判斷如果有一方贏了的情況下提示勝利一秒,然后回到勝利后的最終界面,可以選擇悔棋重新思考下棋位置,也可以選擇重新開始返回主界面等。在有5顆棋子連接成的情況下點擊棋盤區(qū)域不能有反應(yīng)。

      有一方勝利后調(diào)用函數(shù)

      恢復(fù)至最終勝利界面的函數(shù)

      void Recover(void) { u8 m,n; DrawChessBoard();//恢復(fù)棋盤結(jié)束前的模樣 for (m= 0; m < 15; m++) { for (n = 0; n < 15; n++) { if (g_Chess[m][n] > 0) { int num = g_Chess[m][n]; DrawChess(m, n, num-1, 0); } } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      在判斷有一方勝利以后調(diào)用該函數(shù),可以恢復(fù)至最終勝利界面后的函數(shù)。

      void Over_test(void) { int a,b; while(1) { tp_dev.scan(0); a = tp_dev.x[0]; b = tp_dev.y[0]; if(tp_dev.sta&TP_PRES_DOWN) //觸摸屏被按下 { if (a > 5 && a < 85 && b > 285 && b < 310)//重新開始 { ResStart(); } if (a > 87 && a < 135 && b > 285 && b < 310)//悔棋 { RetractChess(); Recover(); Two_test(); } if (a > 187 && a < 236 && b > 285 && b < 310)//返回 { ResStart(); GameInit(); } } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      在恢復(fù)至最終勝利界面后調(diào)用該函數(shù),主要實現(xiàn)的功能是按棋盤范圍內(nèi)沒有反應(yīng),按下方按鈕才有反應(yīng)。主要避免在測試界面判斷勝利以后恢復(fù)至最終勝利界面依舊可以下棋。

      總結(jié)

      通過用STM32F103實現(xiàn)五子棋讓我學(xué)到了很多知識,對如何完成一個工程有了更好的認(rèn)識和理解,最終實現(xiàn)了預(yù)期的所有功能讓自己很有成就感。但是這個項目也有不足之處,不能選擇誰先走誰后走,后期可以再完善一下。

      實際效果視頻鏈接

      基于STM32的五子棋小游戲

      同時紀(jì)念一下第一次手寫代碼,加油!!!沖鴨!

      5G游戲 AI

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【愚公系列】2022年02月 wireshark系列-數(shù)據(jù)抓包分析之FTP協(xié)議01
      下一篇:深度學(xué)習(xí)入門篇,簡單的實例講明白圖像分類。
      相關(guān)文章
      中文字幕无码精品亚洲资源网| 亚洲综合小说久久另类区| 亚洲国产精品不卡在线电影| 亚洲精品国产品国语在线| 国产成人99久久亚洲综合精品 | 在线电影你懂的亚洲| 亚洲成AV人片在线观看无| 中文字幕精品亚洲无线码一区| 国产精品亚洲精品日韩已方| 亚洲熟伦熟女新五十路熟妇| 亚洲 无码 在线 专区| 在线视频亚洲一区| 亚洲av无码偷拍在线观看| 亚洲国产成人无码AV在线| 亚洲av午夜国产精品无码中文字| 亚洲精品无码专区在线播放| 亚洲国产精品无码中文lv| 亚洲欧美日韩久久精品| 色综合久久精品亚洲国产| 亚洲欧美在线x视频| 在线观看亚洲电影| 亚洲精品和日本精品| 国产亚洲精品影视在线产品| 亚洲精品无码午夜福利中文字幕| 亚洲精品国产品国语在线| 亚洲综合在线视频| 亚洲成人网在线播放| 亚洲AV成人无码天堂| 亚洲日本一线产区和二线 | 亚洲GV天堂无码男同在线观看 | 亚洲色偷偷av男人的天堂| 亚洲人成激情在线播放| 亚洲国产乱码最新视频| 亚洲av成人无码网站…| 亚洲精品国产高清不卡在线| 亚洲人成网站在线播放vr| 亚洲福利视频一区| 亚洲成a人片77777群色| 精品亚洲456在线播放| 国产精品亚洲一区二区无码| 国产亚洲美女精品久久久2020|