乐趣区

关于pygame:pygame实现成语填空游戏

最近看到很多人玩成语填字游戏,那么先用 pygame 来做一个吧,花了大半天终于实现了,附下效果图。

偷了下懒程序没有拆分,所有程序写在一个文件里,次要代码如下:


    # -*- coding=utf-8 -*-
    import sys
    import random
    import pygame
    from pygame.locals import *
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    f = open('words.txt')
    all_idiom = f.readlines()
    f.close()
    
    word_dic = {}
    for idiom in all_idiom:
     idiom = idiom.strip().decode('utf-8')
     for word in idiom:
     if word not in word_dic: 
     word_dic[word] = [idiom]
     else:
      word_dic[word].append(idiom)
    
    word_arr = list(word_dic.keys())
    
    header_height = 30
    main_space = 20
    
    block_size = 36
    block_num=12
    bspace = 2
    space = 20
    width = block_size * block_num + main_space * 2
    height = header_height + block_size * block_num + main_space * 2 + (block_size+space) * 3
    
    pygame.init()
    screen = pygame.display.set_mode((width,height))
    screencaption = pygame.display.set_caption(u'成语填空')
    
    font = pygame.font.Font(u'syht.otf', int(block_size*0.8))
    
    dray_gray = 50,50,50
    white = 255,255,255
    #textImage = font.render(u'你好', True, white)
    
    class IdiomInfo(object):
     def __init__(self,idiom):
     self.idiom = idiom
     self.dire = 0
     self.word_arr = []
    
    class WordInfo(object):
     def __init__(self, word, i, j):
     self.i = i
     self.j = j
     self.word = word
     self.is_lock = True
     self.state = -1
     self.hide_index = -1
     self.op_hide_index = -1
    
    class Matrix(object):
     rows = 0
     cols = 0
     data = []
    
     def __init__(self, rows, cols, data=None):
      self.rows = rows
      self.cols = cols
      if data is None: data = [None for i in range(rows * cols)]
      self.data = data
    
     def set_val(self, x, y, val):
      self.data[y * self.cols + x] = val
    
     def get_val(self, x, y):
      return self.data[y * self.cols + x]
    
     def exist_val_four_around(self, x, y, ignore_set):
      move_arr = [(-1,0),(1,0),(0,-1),(0,1)]
    
      for dx,dy in move_arr:
      tx = x + dx
      ty = y + dy
      if (tx,ty) in ignore_set: continue
      if tx < 0 or tx >= self.cols or ty <0 or ty >= self.rows: continue
      if self.data[ty * self.cols + tx]: return True
      return False
    
    def check_new_idiom(matrix, new_idiom, new_dire, word_info):
     windex = new_idiom.index(word_info.word)
     cx,cy = word_info.i, word_info.j
     ignore_set = set([(cx,cy)])
    
     new_idiom_word_arr=[]
     for i in range(-windex,-windex+len(new_idiom)): 
     if i==0: 
     new_idiom_word_arr.append(word_info)
     else:
     tx = cx+i if new_dire == 0 else cx
     if tx < 0 or tx >= block_num: return None,None
    
     ty = cy if new_dire == 0 else cy+i
     if ty < 0 or ty >= block_num: return None,None
    
     if matrix.exist_val_four_around(tx, ty, ignore_set): return None,None
    
     old_word_info = matrix.get_val(tx, ty)
     if old_word_info:
     return None,None
    
     new_word_info = WordInfo(new_idiom[i+windex], tx, ty)
     new_idiom_word_arr.append(new_word_info)
    
    
     return new_idiom_word_arr,windex
    
    def add_idiom_to_matrix(matrix, word_dic, idiom_dic, idiom_num):
     if idiom_num == 0: return 0
     for idiom,idiom_info in idiom_dic.items():
     dire = idiom_info.dire
     new_dire = 1 - dire
     for word_info in idiom_info.word_arr:
     word = word_info.word
     idiom_list = word_dic[word]
     for new_idiom in idiom_list:
     if new_idiom in idiom_dic: continue
     new_idiom_word_arr,windex = check_new_idiom(matrix, new_idiom, new_dire, word_info)
     if new_idiom_word_arr:
      new_idiom_info = IdiomInfo(new_idiom)
      new_idiom_info.dire = new_dire
      for new_index in range(len(new_idiom_word_arr)):
      new_word_info = new_idiom_word_arr[new_index]
      if new_index == windex:
      new_idiom_info.word_arr.append(word_info)
      else:
      matrix.set_val(new_word_info.i, new_word_info.j , new_word_info)
      new_idiom_info.word_arr.append(new_word_info)
      idiom_dic[new_idiom] = new_idiom_info
    
      return len(new_idiom) -1 + add_idiom_to_matrix(matrix, word_dic, idiom_dic, idiom_num - 1)
    
     return 0
    
    def get_idiom_matrix(word_arr, word_dic, idiom_num):
     cx = 4
     cy = 4
     matrix = Matrix(block_num, block_num)
     n = random.randint(0,len(word_arr)-1)
     word = word_arr[n]
     idiom = word_dic[word][0]
     idiom_dic={}
     idiom_dic[idiom] = IdiomInfo(idiom)
     wn = len(idiom)
     last_i = -100
     for i in range(len(idiom)):
     word_info = WordInfo(idiom[i],cx-1+i,cy)
     matrix.set_val(cx-1+i,cy,word_info)
     idiom_dic[idiom].word_arr.append(word_info)
    
     wn += add_idiom_to_matrix(matrix, word_dic, idiom_dic, idiom_num-1)
     return matrix, idiom_dic, wn
    
    
    bg_image = pygame.image.load('bg.jpeg')
    bg_image = pygame.transform.scale(bg_image,(width, height))
    
    bg2_image = pygame.image.load('bg2.jpeg')
    bg2_image = pygame.transform.scale(bg2_image,(block_size*block_num,block_size*block_num))
    
    block_bg_image = pygame.image.load('tzg.jpg')
    block_bg_image = pygame.transform.scale(block_bg_image,(block_size-bspace*2,block_size-bspace*2))
    
    def get_hide_arr(matrix, idiom_dic, all_word_num, percent):
     hide_arr = []
     for k,v in idiom_dic.items():
     n = random.randint(0, len(v.word_arr)-1)
     word_info = v.word_arr[n]
     if word_info.hide_index != -1:continue
     word = word_info.word
     info = matrix.get_val(word_info.i,word_info.j)
     info.word = ''
     info.hide_index = len(hide_arr)
     info.is_lock = False
     hide_arr.append([word_info.i,word_info.j,word,None])
    
     tmp_arr = []
     for i in range(block_num):
     for j in range(block_num):
     info = matrix.get_val(i,j)
     if info and info.word:
     tmp_arr.append((i,j,info.word))
    
     while len(hide_arr) < all_word_num*percent:
     n = random.randint(0,len(tmp_arr)-1)
     i,j,word = tmp_arr.pop(n)
     info = matrix.get_val(i,j)
     info.word = ''
     info.hide_index = len(hide_arr)
     info.is_lock = False
     hide_arr.append([i,j,word,None])
    
     return hide_arr 
    
    def get_next_select(matrix, x, y):
     arr = []
     for i in range(block_num):
     for j in range(block_num):
     info = matrix.get_val(i, j)
     if info is not None and len(info.word) == 0:
     dist = (i-x)*(i-x)+(j-y)*(j-y)
     if i<x: dist+=0.2
     if j<y: dist+=0.4
     arr.append((i,j,dist))
     if len(arr) == 0:
     return None
     arr.sort(cmp=lambda x,y:cmp(x[-1],y[-1]))
     return (arr[0][0],arr[0][1])
    
    def check_idiom():
     for idiom, idiom_info in idiom_dic.items():
     tmp_idiom_str = ''
     word_arr = idiom_info.word_arr
     for word_info in word_arr:
     word = word_info.word
     if len(word) > 0:
     tmp_idiom_str+=word
     if len(tmp_idiom_str) == len(idiom):
     state = 1 if tmp_idiom_str == idiom else 2
     else:
     state = 0
    
     for word_info in word_arr:
     if word_info.state != 1: word_info.state = state
    
     for idiom, idiom_info in idiom_dic.items():
     word_arr = idiom_info.word_arr
     for word_info in word_arr:
     if word_info.state != 1:
     return False
     return True
    
    stage = 1
    
    def init(new_stage):
     idiom_num = (new_stage/5)+3
     if new_stage>100:
     percent = 0.7
     else:
     percent = 0.2+(new_stage*1.0/100)*(0.7-0.2)
     matrix,idiom_dic,all_word_num = get_idiom_matrix(word_arr, word_dic, idiom_num)
     hide_arr = get_hide_arr(matrix, idiom_dic, all_word_num, percent)
     select_rect = hide_arr[0][0],hide_arr[0][1]
     stage_textImage = pygame.font.Font(u'syht.otf', 30).render(u'第 %s 关'%new_stage, True, dray_gray)
     return matrix,idiom_dic,all_word_num,hide_arr,select_rect,stage_textImage
    
    matrix,idiom_dic,all_word_num,hide_arr,select_rect,stage_textImage = init(stage)
    
    stage_font_width, stage_font_height = stage_textImage.get_size()
    stage_x = (width - stage_font_width)/2
    stage_y = (header_height - stage_font_height)/2+main_space/2
    while True:
     for event in pygame.event.get():
     if event.type == pygame.QUIT:
      pygame.quit()
      exit()
    
     if event.type == MOUSEBUTTONDOWN:
     pressed_array = pygame.mouse.get_pressed()
     if pressed_array[0]:
     x, y = pygame.mouse.get_pos()
    
     for i in range(block_num):
      for j in range(block_num):
      bx = main_space + block_size*i+bspace
      by = header_height + main_space + block_size*j+bspace
      if x >= bx and x <= bx+block_size-bspace*2 and y >= by and y<= by+block_size-bspace*2:
      info = matrix.get_val(i, j)
      if info and info.state != 1 and info.hide_index >= 0:
      if info.op_hide_index>=0:
       hide_arr[info.op_hide_index][-1] = None
       info.word = ''
       info.op_hide_index=-1
       check_idiom()
      select_rect = i,j
      break
    
     sx = main_space
     sy = header_height + main_space+ block_size*block_num +space
     n = 0
     for hi in range(len(hide_arr)):
      tmp_x = sx + (n%block_num)*block_size
      tmp_y = sy + (n/block_num)*block_size
      if hide_arr[hi][-1] is None and x >= tmp_x and x <= tmp_x+block_size-bspace*2 and y >= tmp_y and y<= tmp_y+block_size-bspace*2:
      info = matrix.get_val(select_rect[0],select_rect[1])
      info.word = hide_arr[hi][2]
      info.op_hide_index = hi
      info.state = 0
      hide_arr[hi][-1] = select_rect
      new_select_rect = get_next_select(matrix, select_rect[0],select_rect[1])
      select_rect = new_select_rect
      flag = check_idiom()
      if flag:
      stage += 1
      matrix,idiom_dic,all_word_num,hide_arr,select_rect,stage_textImage = init(stage)
      break
    
      n += 1
    
    
     screen.blit(bg_image, (0,0))
     screen.blit(stage_textImage, (stage_x,stage_y))
    
     panel = screen.subsurface((main_space,header_height+main_space,block_size*block_num,block_size*block_num))
     panel.blit(bg2_image, (0,0))
    
     for i in range(block_num):
     for j in range(block_num):
     info = matrix.get_val(i,j)
     if info is not None:
     bx = block_size*i+bspace
     by = block_size*j+bspace
     panel.blit(block_bg_image, (bx,by))
     
     if info.state == 1:
      textImage = font.render(info.word, True, (30,144,30))
     elif info.state == 2:
      textImage = font.render(info.word, True, (255,0,0))
     elif info.is_lock == 1:
      textImage = font.render(info.word, True, (150,150,150))
     else:
      textImage = font.render(info.word, True, dray_gray)
    
     tw, th = textImage.get_size()
     dx=(block_size-bspace*2-tw)/2
     dy=(block_size-bspace*2-th)/2
     panel.blit(textImage, (bx+dx,by+dy))
     if (i,j) == select_rect:
      pygame.draw.rect(panel,(255,0,0),(bx,by,block_size-bspace*2,block_size-bspace*2),2)
    
     sx = main_space
     sy = header_height + main_space+ block_size*block_num +space
     n = 0
     for i,j,word,op in hide_arr:
     screen.blit(block_bg_image, (sx + (n%block_num)*block_size,sy + (n/block_num)*block_size))
     if op is None:
     textImage = font.render(word, True, dray_gray)
     tw, th = textImage.get_size()
     dx=(block_size-bspace*2-tw)/2
     dy=(block_size-bspace*2-th)/2
     screen.blit(textImage, (dx+sx+ (n%block_num)*block_size,dy+sy+ (n/block_num)*block_size))
     n+=1
    
     pygame.display.update()

代码就这么多了,不过这边用到几个额定的依赖:
bg.jpeg 用于做整个界面的背景
bg2.jpeg 用于做上半局部的背景
tzg.jpg 每个文字的格子的背景
words.txt 一个成语的列表文件(每行一条成语),如果换成诗词或者歇后语什么的也是没有问题的
syht.otf 一个字体库,用于失常显示中文

如果闲格子太多或者太小,能够调一下这两个参数


    block_size = 32
    block_num=12

block_size 示意格子的大小
block_num 上半局部的区域横竖最多显示多少个格子

block_size = 26,block_num=18 的效果图:

block_size = 40,block_num=10 的效果图:
i

退出移动版