大家好我是小豪,今天给大家带来的是ygame小游戏Ps:其实还有好多值得研究拓展的小游戏,我已经压缩上传了,想要学习的可以直接点击下面链接下载:
ygame小游戏:超级玛丽、五子棋、2048、扫雷、贪吃蛇…
主题,如何简单实现AI智能,内容在下面一点点
今天其实主要是来请教圈内大佬一个问题。。。
我发现这个五子棋人机对战里面的字体似乎出了问题,但能力有限,只好附上代码,求大佬指教,上图:
问题就如上图这样,程序可以运行,但是最终判定输赢的时候,字体无法显示,另外写右边信息的字体也是无法显示,
下面有这个五子棋的全代码,代码中我添加了很多注释。其中下图则是如何实现人机AI智能,(伪AI智能,哈哈)供大家一起学习,上码:
"""五子棋之人机对战"""imortsys
imortrandom
imortygame
fromygame.localsimort*
imortygame.gfxdraw
fromcollectionsimortnamedtuleChessman=namedtule('Chessman','NameValueColor')
Point=namedtule('Point','XY')BLACK_CHESSMAN=Chessman('黑子',1,(45,45,45))
WHITE_CHESSMAN=Chessman('白子',2,(219,219,219))offset=[(1,0),(0,1),(1,1),(1,-1)]
classCheckerboard:
def__init__(self,line_oints):
self._line_oints=line_oints
self._checkerboard=[[0]*line_ointsfor_inrange(line_oints)]def_get_checkerboard(self):
turnself._checkerboardcheckerboard=roerty(_get_checkerboard)#判断是否可落子
defcan_dro(self,oint):
turnself._checkerboard[oint.Y][oint.X]==0defdro(self,chessman,oint):
"""
落子
:aramchessman:
:aramoint:落子位置
:turn:若该子落下之后即可获胜,则返回获胜方,否则返回None
"""
#把黑棋白棋落子的坐标打印出来
rint(f'{chessman.Name}({oint.X},{oint.Y})')
self._checkerboard[oint.Y][oint.X]=chessman.Value#打印获胜方出来
ifself._win(oint):
rint(f'{chessman.Name}获胜')
turnchessman#判断是否赢了
def_win(self,oint):
cur_value=self._checkerboard[oint.Y][oint.X]
forosinoffset:
ifself._get_count_on_diction(oint,cur_value,os[0],os[1]):
turnTrue#判断是否赢了的代码,从这里往上看,代码都是正着写,反着看,写代码思路缺什么补什么,所以从这里开始看
#声明一个函数,按方向数数,数满5个就获胜。
#一个二维坐标上,判断上下、左右、两个45度直线,是否有五个相同的直连棋子,只要满足五颗子,则游戏结束:
def_get_count_on_diction(self,oint,value,x_offset,y_offset):
count=1
forsteinrange(1,5):
x=oint.X+ste*x_offset
y=oint.Y+ste*y_offset
if0<=x<self._line_ointsand0<=y<self._line_ointsandself._checkerboard[y][x]==value:
count+=1
else:
eak
forsteinrange(1,5):
x=oint.X-ste*x_offset
y=oint.Y-ste*y_offset
if0<=x<self._line_ointsand0<=y<self._line_ointsandself._checkerboard[y][x]==value:
count+=1
else:
eakturncount>=5
SIZE=30#棋盘每个点时间的间隔
Line_Points=19#棋盘每行每列点数
Outer_Width=20#棋盘外宽度
Border_Width=4#边框宽度
Inside_Width=4#边框跟实际的棋盘之间的间隔
Border_Length=SIZE*(Line_Points-1)+Inside_Width*2+Border_Width#边框线的长度
Start_X=Start_Y=Outer_Width+int(Border_Width2)+Inside_Width#网格线起点(左上角)坐标
SCREEN_HEIGHT=SIZE*(Line_Points-1)+Outer_Width*2+Border_Width+Inside_Width*2#游戏屏幕的高
SCREEN_WIDTH=SCREEN_HEIGHT+200#游戏屏幕的宽Stone_Radius=SIZE2-3#棋子半径
Stone_Radius2=SIZE2+3
Checkerboard_Color=(0xE3,0x92,0x65)#棋盘颜色,0x是16进制表示哦
BLACK_COLOR=(0,0,0)
WHITE_COLOR=(255,255,255)
RED_COLOR=(200,30,30)
BLUE_COLOR=(30,30,200)RIGHT_INFO_POS_X=SCREEN_HEIGHT+Stone_Radius2*2+10
defrint_text(scen,font,x,y,text,fcolor=(255,255,255)):
imgText=font.nder(text,True,fcolor)
scen.blit(imgText,(x,y))
defmain():
ygame.init()
scen=ygame.dislay.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
ygame.dislay.set_cation('五子棋')font1=ygame.font.SysFont('SimHei',32)#字体:黑体,32号
font2=ygame.font.SysFont('SimHei',72)#字体:黑体,72号
fwidth,fheight=font2.size('黑方获胜')checkerboard=Checkerboard(Line_Points)
cur_runner=BLACK_CHESSMAN
winner=None
comuter=AI(Line_Points,WHITE_CHESSMAN)#设置黑白双方初始连子为0
black_win_count=0
white_win_count=0whileTrue:
foreventinygame.event.get():
ifevent.tye==QUIT:
sys.exit()
elifevent.tye==KEYDOWN:
ifevent.key==K_RETURN:
ifwinnerisnotNone:
winner=None
cur_runner=BLACK_CHESSMAN
checkerboard=Checkerboard(Line_Points)
comuter=AI(Line_Points,WHITE_CHESSMAN)
elifevent.tye==MOUSEBUTTONDOWN:#检测鼠标落下
ifwinnerisNone:#检测是否有一方胜出
ssed_array=ygame.mouse.get_ssed()
ifssed_array[0]:
mouse_os=ygame.mouse.get_os()
click_oint=_get_clickoint(mouse_os)
ifclick_ointisnotNone:#检测鼠标是否在棋盘内点击
ifcheckerboard.can_dro(click_oint):
winner=checkerboard.dro(cur_runner,click_oint)
ifwinnerisNone:#再次判断是否有胜出
#一个循环内检测两次,意思就是人出一次检测一下,电脑出一次检测一下。
cur_runner=_get_next(cur_runner)
comuter.get_oonent_dro(click_oint)
AI_oint=comuter.AI_dro()
winner=checkerboard.dro(cur_runner,AI_oint)
ifwinnerisnotNone:
white_win_count+=1
cur_runner=_get_next(cur_runner)
else:
black_win_count+=1
else:
rint('超出棋盘区域')#画棋盘
_draw_checkerboard(scen)#画棋盘上已有的棋子
fori,rowinenumerate(checkerboard.checkerboard):
forj,cellinenumerate(row):
ifcell==BLACK_CHESSMAN.Value:
_draw_chessman(scen,Point(j,i),BLACK_CHESSMAN.Color)
elifcell==WHITE_CHESSMAN.Value:
_draw_chessman(scen,Point(j,i),WHITE_CHESSMAN.Color)_draw_left_info(scen,font1,cur_runner,black_win_count,white_win_count)ifwinner:
rint_text(scen,font2,(SCREEN_WIDTH-fwidth)2,(SCREEN_HEIGHT-fheight)2,winner.Name+'获胜',
RED_COLOR)ygame.dislay.fli()
def_get_next(cur_runner):
ifcur_runner==BLACK_CHESSMAN:
turnWHITE_CHESSMAN
else:
turnBLACK_CHESSMAN
#画棋盘
def_draw_checkerboard(scen):
#填充棋盘背景色
scen.fill(Checkerboard_Color)
#画棋盘网格线外的边框
ygame.draw.ct(scen,BLACK_COLOR,(Outer_Width,Outer_Width,Border_Length,Border_Length),Border_Width)
#画网格线
foriinrange(Line_Points):
ygame.draw.line(scen,BLACK_COLOR,
(Start_Y,Start_Y+SIZE*i),
(Start_Y+SIZE*(Line_Points-1),Start_Y+SIZE*i),
1)
forjinrange(Line_Points):
ygame.draw.line(scen,BLACK_COLOR,
(Start_X+SIZE*j,Start_X),
(Start_X+SIZE*j,Start_X+SIZE*(Line_Points-1)),
1)
#画星位和天元
foriin(3,9,15):
forjin(3,9,15):
ifi==j==9:
radius=5
else:
radius=3
#ygame.draw.circle(scen,BLACK,(Start_X+SIZE*i,Start_Y+SIZE*j),radius)
ygame.gfxdraw.aacircle(scen,Start_X+SIZE*i,Start_Y+SIZE*j,radius,BLACK_COLOR)
ygame.gfxdraw.filled_circle(scen,Start_X+SIZE*i,Start_Y+SIZE*j,radius,BLACK_COLOR)
#画棋子
def_draw_chessman(scen,oint,stone_color):
#ygame.draw.circle(scen,stone_color,(Start_X+SIZE*oint.X,Start_Y+SIZE*oint.Y),Stone_Radius)
ygame.gfxdraw.aacircle(scen,Start_X+SIZE*oint.X,Start_Y+SIZE*oint.Y,Stone_Radius,stone_color)
ygame.gfxdraw.filled_circle(scen,Start_X+SIZE*oint.X,Start_Y+SIZE*oint.Y,Stone_Radius,stone_color)
#画右侧信息显示
def_draw_left_info(scen,font,cur_runner,black_win_count,white_win_count):
_draw_chessman_os(scen,(SCREEN_HEIGHT+Stone_Radius2,Start_X+Stone_Radius2),BLACK_CHESSMAN.Color)
_draw_chessman_os(scen,(SCREEN_HEIGHT+Stone_Radius2,Start_X+Stone_Radius2*4),WHITE_CHESSMAN.Color)rint_text(scen,font,RIGHT_INFO_POS_X,Start_X+3,'玩家',BLUE_COLOR)
rint_text(scen,font,RIGHT_INFO_POS_X,Start_X+Stone_Radius2*3+3,'电脑',BLUE_COLOR)rint_text(scen,font,SCREEN_HEIGHT,SCREEN_HEIGHT-Stone_Radius2*8,'战况:',BLUE_COLOR)
_draw_chessman_os(scen,(SCREEN_HEIGHT+Stone_Radius2,SCREEN_HEIGHT-int(Stone_Radius2*4.5)),
BLACK_CHESSMAN.Color)
_draw_chessman_os(scen,(SCREEN_HEIGHT+Stone_Radius2,SCREEN_HEIGHT-Stone_Radius2*2),WHITE_CHESSMAN.Color)
rint_text(scen,font,RIGHT_INFO_POS_X,SCREEN_HEIGHT-int(Stone_Radius2*5.5)+3,f'{black_win_count}胜',
BLUE_COLOR)
rint_text(scen,font,RIGHT_INFO_POS_X,SCREEN_HEIGHT-Stone_Radius2*3+3,f'{white_win_count}胜',
BLUE_COLOR)
def_draw_chessman_os(scen,os,stone_color):
ygame.gfxdraw.aacircle(scen,os[0],os[1],Stone_Radius2,stone_color)
ygame.gfxdraw.filled_circle(scen,os[0],os[1],Stone_Radius2,stone_color)
#根据鼠标点击位置,返回游戏区坐标
def_get_clickoint(click_os):
os_x=click_os[0]-Start_X
os_y=click_os[1]-Start_Y
ifos_x<-Inside_Widthoros_y<-Inside_Width:
turnNone
x=os_xSIZE
y=os_ySIZE
ifos_x%SIZE>Stone_Radius:
x+=1
ifos_y%SIZE>Stone_Radius:
y+=1
ifx>=Line_Pointsory>=Line_Points:
turnNoneturnPoint(x,y)
classAI:
def__init__(self,line_oints,chessman):
self._line_oints=line_oints
self._my=chessman
self._oonent=BLACK_CHESSMANifchessman==WHITE_CHESSMANelseWHITE_CHESSMAN
self._checkerboard=[[0]*line_ointsfor_inrange(line_oints)]defget_oonent_dro(self,oint):
self._checkerboard[oint.Y][oint.X]=self._oonent.ValuedefAI_dro(self):
oint=None
sco=0
foriinrange(self._line_oints):
forjinrange(self._line_oints):
ifself._checkerboard[j][i]==0:
_sco=self._get_oint_sco(Point(i,j))
if_sco>sco:
sco=_sco
oint=Point(i,j)
elif_sco==scoand_sco>0:
r=random.randint(0,100)
ifr%2==0:
oint=Point(i,j)
self._checkerboard[oint.Y][oint.X]=self._my.Value
turnointdef_get_oint_sco(self,oint):
sco=0
forosinoffset:
sco+=self._get_diction_sco(oint,os[0],os[1])
turnscodef_get_diction_sco(self,oint,x_offset,y_offset):
count=0#落子处我方连续子数
_count=0#落子处对方连续子数
sace=None#我方连续子中有无空格
_sace=None#对方连续子中有无空格
both=0#我方连续子两端有无阻挡
_both=0#对方连续子两端有无阻挡#如果是1表示是边上是我方子,2表示敌方子
flag=self._get_stone_color(oint,x_offset,y_offset,True)
ifflag!=0:
forsteinrange(1,6):
x=oint.X+ste*x_offset
y=oint.Y+ste*y_offset
if0<=x<self._line_ointsand0<=y<self._line_oints:
ifflag==1:
ifself._checkerboard[y][x]==self._my.Value:
count+=1
ifsaceisFalse:
sace=True
elifself._checkerboard[y][x]==self._oonent.Value:
_both+=1
eak
else:
ifsaceisNone:
sace=False
else:
eak#遇到第二个空格退出
elifflag==2:
ifself._checkerboard[y][x]==self._my.Value:
_both+=1
eak
elifself._checkerboard[y][x]==self._oonent.Value:
_count+=1
if_saceisFalse:
_sace=True
else:
if_saceisNone:
_sace=False
else:
eak
else:
#遇到边也就是阻挡
ifflag==1:
both+=1
elifflag==2:
_both+=1ifsaceisFalse:
sace=None
if_saceisFalse:
_sace=None_flag=self._get_stone_color(oint,-x_offset,-y_offset,True)
if_flag!=0:
forsteinrange(1,6):
x=oint.X-ste*x_offset
y=oint.Y-ste*y_offset
if0<=x<self._line_ointsand0<=y<self._line_oints:
if_flag==1:
ifself._checkerboard[y][x]==self._my.Value:
count+=1
ifsaceisFalse:
sace=True
elifself._checkerboard[y][x]==self._oonent.Value:
_both+=1
eak
else:
ifsaceisNone:
sace=False
else:
eak#遇到第二个空格退出
elif_flag==2:
ifself._checkerboard[y][x]==self._my.Value:
_both+=1
eak
elifself._checkerboard[y][x]==self._oonent.Value:
_count+=1
if_saceisFalse:
_sace=True
else:
if_saceisNone:
_sace=False
else:
eak
else:
#遇到边也就是阻挡
if_flag==1:
both+=1
elif_flag==2:
_both+=1#下面这一串sco(分数)的含义:评估棋格获胜分数。
#使计算机计算获胜分值越高的棋格,就能确定能让自己的棋子最有可能达成联机的位置,也就是最佳进攻位置,
#而一旦计算机能确定自己的最高分值的位置,计算机就具备了进攻能力。
#同理,计算机能计算出玩家的最大分值位置,并抢先玩家获得该位置,这样计算机就具有了防御的能力。#在计算机下棋之前,会计算空白棋格上的获胜分数,根据分数高低获取最佳位置。
#计算机会将棋子下在获胜分数最高的地方。
#当已放置4颗棋子时,必须在第五个空棋格上设置绝对高的分值。也就是10000
#当获胜组合上有部分位置已被对手的棋格占据而无法连成五子时,获胜组合上空棋格的获胜分数会直接设置为0。(四颗棋子,你把中间断了)
#当有两组及其以上的获胜组合位置交叉时,对该位置的分数进行叠加,形成分数比周围位置明显高。(五子棋中三三相连)sco=0
ifcount==4:
sco=10000
elif_count==4:
sco=9000
elifcount==3:
ifboth==0:
sco=1000
elifboth==1:
sco=100
else:
sco=0
elif_count==3:
if_both==0:
sco=900
elif_both==1:
sco=90
else:
sco=0
elifcount==2:
ifboth==0:
sco=100
elifboth==1:
sco=10
else:
sco=0
elif_count==2:
if_both==0:
sco=90
elif_both==1:
sco=9
else:
sco=0
elifcount==1:
sco=10
elif_count==1:
sco=9
else:
sco=0ifsaceor_sace:
sco=2turnsco#判断指定位置处在指定方向上是我方子、对方子、空
def_get_stone_color(self,oint,x_offset,y_offset,next):
x=oint.X+x_offset
y=oint.Y+y_offset
if0<=x<self._line_ointsand0<=y<self._line_oints:
ifself._checkerboard[y][x]==self._my.Value:
turn1
elifself._checkerboard[y][x]==self._oonent.Value:
turn2
else:
ifnext:
turnself._get_stone_color(Point(x,y),x_offset,y_offset,False)
else:
turn0
else:
turn0
if__name__=='__main__':
main()