Python菜鸟快乐游戏编程_pygame(博主录制,2K分辨率,超高清)
https://study.163.com/course/courseMain.htm?courseId=1006188025&share=2&shareId=400000000398149
上周,有个朋友对我说,Toby,你弄游戏编程这玩意没啥实用性,应该录制更多Python机器学习和人工智能的视频。我对那位朋友说,游戏就是人工智能最好的训练场所。不管扫雷,奥赛罗棋,围棋,象棋,跳棋,星际争霸都是基于算法的,通过人工智能AI,我们可以获取更高胜率。同时我告诫各位年轻朋友,游戏是会上瘾的。一个商业游戏如果不能让玩家上瘾,那就是一款失败游戏。因此我们会看到无数年轻人在网吧沉醉不知归路。我也有过类似经历,上瘾后,如果不能继续玩下去,全身都难受,继续玩下去,全身软绵绵想吐。
游戏就是别人设计的程序。与其活在别人程序里,不如开发自己游戏,还能学习编程和算法,获取一年几十万高薪。
此节课以扫雷为例,讲解神经网络算法生成模型,通过模型来自动扫雷,这就是简单人工智能。
感谢作者Nolan Baker对pygame社区贡献,为大家奉献这款游戏,作者邮箱是:
<hendersonhasselbalch@gmail.com>
朋友们可以训练数据,尝试更多算法,最终搞一个算法夺旗比赛,看看谁的算法胜率更高。
首先打开smartsweeper文件夹,进入子文件夹smartsweeper beta,所有脚本都放在这里
neural_network.py 这脚本主要是通过神经网络算法,生成一个模型。
# -*- coding: utf-8 -*-
"""
Created on Sun Oct 7 10:16:24 2018
作者邮件:231469242@qq.com
作者微信公众号:PythonEducation
""" #
# neural_network.py
#
# Copyright 2010 Nolan Baker <hendersonhasselbalch@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA. import random, os, math
from numpy import *
import numpy.random as nrand ################################################################################
# Useful Vector Functions
################################################################################
def sigmoid(x):
return 1.0 / (1 + math.exp(-x))
sigmoid = vectorize(sigmoid, otypes=[float]) def sigPrime(x):
# in terms of the output of the sigmoid function
# otherwise would be sig(x) - sig^2(x)
return x - x ** 2
sigPrime = vectorize(sigPrime, otypes=[float]) def oneMinus(x):
return 1 - x
oneMinus = vectorize(oneMinus, otypes=[float]) def sub(x,y):
return x - y
sub = vectorize(sub, otypes=[float]) ################################################################################
# Neural Network
################################################################################
class NeuralNet:
def __init__(self, i, h, o):
self.w_ih = mat(nrand.uniform(-.05, .05,(i,h)))
self.w_ho = mat(nrand.uniform(-.05, .05,(h,o)))
self.m_ih = mat(zeros((i,h)))
self.m_ho = mat(zeros((h,o))) def getOut(self, i):
self.h = sigmoid(mat(i) * self.w_ih)
return sigmoid(self.h * self.w_ho).tolist()[0] def train(self, i, t, a = .1, b = .01): # get output of our neural network
out = mat(self.getOut(i)) # calc deltas
d_o = mat(asarray(out) * asarray(oneMinus(out)) *
asarray(sub(mat(t), out)))
d_h = mat(asarray(self.h) * asarray(oneMinus(self.h)) *
asarray(d_o * self.w_ho.T)) # update weights
c_ih = mat(i).T * d_h
self.w_ih = add(add(self.w_ih, a * c_ih), b * self.m_ih)
self.m_ih = c_ih
c_ho = self.h.T * d_o
self.w_ho = add(add(self.w_ho, a * c_ho), b * self.m_ho)
self.m_ho = c_ho ################################################################################
# example
################################################################################
def main(): nn = NeuralNet(2,10,1)
examples = [([0,1], [1]),
([1,1], [0]),
([1,0], [1]),
([0,0], [0])] for i in range(10000):
print i
x = random.randint(0,4)
nn.train(examples[x][0], examples[x][1], 3) print nn.getOut([0,1])
print nn.getOut([1,1])
print nn.getOut([1,0])
print nn.getOut([0,0]) if __name__ == '__main__':
main()
agent.py生成一个机器人,代理玩家自动扫雷
# -*- coding: utf-8 -*-
"""
Created on Sun Oct 7 10:16:24 2018
作者邮件:231469242@qq.com
作者微信公众号:PythonEducation
"""
#
# agent.py
#
# Copyright 2010 Nolan Baker <hendersonhasselbalch@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA. import random, pygame, os
from pygame.locals import *
from game import *
from state import *
from neural_network import * # FLOATING POINT NUMBERS BETWEEN 0 and 1
THRESH = .18
INITIAL = 1
ALPHA = .05
BETA = .01
OPEN_MIND = 1
HUG_EDGE = 1
BRN2GRN = 0
GREED = 0
EXPLORE = .7
NUM_POS = 5
THRESH = .16
INITIAL = 1
TO_DIG = 1 # low numbers make digging difficult
TO_FLAG = 1 # low numbers make flagging difficult
TO_UNFLAG = 1 # low numbers make unflagging easy
WEIGHT = .005
ALLOW_REPEATS = 0 #percentage of repeats allowed # FLOATS LARGER THAN 1
SPEED_AMT = 1.00191 # increased threshold change
CHANGE = 1.000173 # normal threshold change # INTEGERS
NUM_POS = 8
MAX_MOVES = 42000
MOVES_LEARNED = 4000
SPEED_MOVES = 15000
INPUT_GRID = 5
OUTPUT_GRID = 3 # BOOLEAN
SHARE_MAP = True
RESET_MOVES = False # do you want your move list to empty after each game?
CHEAT = False ################################################################################
# Intelligent Agent
################################################################################ class Agent:
def __init__(self, game):
self.game = game
self.human = 0
self.clearMoves()
self.name2num_dict = {}
names = "012345678f_"
self.in_size = len(names)
for i in range(len(names)):
nodes = ([0] * 11)
nodes[i] = 1
self.name2num_dict[names[i]] = nodes
a = (INPUT_GRID**2)*(11)
b = OUTPUT_GRID**2
self.nn = NeuralNet(a,a,b)
self.cheat = CHEAT
self.memory = []
self.alpha = ALPHA
self.beta = BETA
self.move_list = []
def switch(self):
self.human = 1 - self.human def clearMoves(self):
self.num_moves = 0
self.closed = []
self.thresh = INITIAL #* random.random()
if self.human and self.game.draw_board:
x, y = pygame.mouse.get_pos()
if self.game.torus:
x %= self.game.width
y %= self.game.height
else:
if x >= self.game.width: x = self.game.width - 1
elif x < 0: x = 0
if y >= self.game.height: y = self.game.height - 1
elif y < 0: y = 0
s = (x, y) else:
#s = (random.randint(0, self.game.width),
# random.randint(0, self.game.height))
s = (0,0)
self.old_pos = s
self.pos = s
self.old_action = "L"
self.action = "L"
if RESET_MOVES:
self.move_list = []
if not SHARE_MAP: self.guess = {}
self.visited = {}
self.certainty = {}
for i in range(self.game.width):
for j in range(self.game.height):
if not SHARE_MAP: self.guess[(i,j)] = .5
self.visited[(i,j)] = 0
self.certainty[(i,j)] = .5 def mouse2Grid(self, pos):
x, y = pos
x = int(x / self.game.tile_size)
y = int(y / self.game.tile_size)
return (x, y) def getArea(self,x,y,n):
area = []
for j in range(n):
b = y + j - int(n / 2)
for i in range(n):
a = x + i - int(n / 2)
if self.game.torus:
a %= self.game.width
b %= self.game.height
area.append((a, b))
return area def boardArea(self):
area = []
for j in range(self.game.height):
for i in range(self.game.width):
area.append((i,j))
return area def threshClick(self):
x,y = self.pos
# get the guess for the space you're on
if SHARE_MAP:
out = self.game.guess[self.pos]
else: out = self.guess[self.pos] name = self.game.board[self.pos]
m = self.num_moves
speed = 1
if m == SPEED_MOVES:
print "speeding up"
if m > SPEED_MOVES:
speed = SPEED_AMT
self.thresh *= CHANGE * speed
if m == MAX_MOVES:
print "giving up"
if m < MAX_MOVES:
if out <= self.thresh * TO_DIG and name != "f":
#print "dig"
self.close(self.pos)
cleared = self.game.dig(self.pos) # how many spaces we cleared
#self.visited[(x,y)] += 5
#if name not in "012345678" and m > SPEED_MOVES:
if cleared != 0:
self.thresh = THRESH * speed
elif (out * TO_UNFLAG <= self.thresh and name == "f"):
#print "unflag"
self.open(self.pos)
self.game.mark(self.pos)
#self.thresh = THRESH * speed
#self.wholeBoard()
elif (out * TO_FLAG >= (1 - self.thresh) and name != "f"):
#print "flag"
self.close(self.pos)
self.game.mark(self.pos)
#self.visited[self.pos] += 5
self.thresh = THRESH * speed
#self.wholeBoard() # if you've gone so many moves without ending the game, do it
elif name == "f":
self.game.mark(self.pos)
self.game.throwTowel()
else:
self.game.dig(self.pos)
self.game.throwTowel() if name == "0":
pass#self.visited[(x,y)] += 10 def simMove(self):
############################################################
# MOVEMENT
############################################################
x,y = self.pos
# if you're on green, move to brown (most of the time)
area = self.getArea(x,y,3)
von_neumann = [(x,y+1),(x,y-1),(x+1,y),(x-1,y)]
possible = []
if random.random() < HUG_EDGE:
for pos in area:
if self.pos == pos:
continue
try:
a = self.game.board[self.pos]
grn = "_f"
brn = "012345678"
if (a in grn) and (self.game.board[pos] in brn):
possible.append(pos)
if (random.random < BRN2GRN and (a in brn) and
(self.game.board[pos] in grn) and
(pos in von_neumann)):
possible.append(pos)
except: pass # if this isn't possible, anywhere is fine
if len(possible) == 0 or random.random < EXPLORE:
possible = area # find the spot you've visited least
m = 9999999999
s = []
for pos in possible:
if pos == self.pos:
continue
try:
v = self.visited[pos]
if v < m:
m = v
s = [pos]
elif v == m:
s.append(pos)
except:
pass
random.shuffle(s) # move to the best guess on the board
if random.random() < GREED:
random.shuffle(self.best_guesses)
self.pos = self.best_guesses[0] # and go to it
else:
self.pos = s[0]
#self.visited[self.pos] += 1 def scanMove(self):
x, y = self.pos
x = (x + 1) % self.game.width
if x == 0:
y = (y + 1) % self.game.height
self.pos = (x, y) def wholeBoard(self):
p = []
for i in range(self.game.width):
for j in range(self.game.height):
p.append((i,j))
random.shuffle(p)
for s in p:
self.getNNOutOf(s) def getNNOutOf(self, p):
x,y = p # figure out where your are and what's around you
self.area = self.getArea(x,y,OUTPUT_GRID)
self.area2 = self.getArea(x,y,INPUT_GRID) # GET INPUT FROM AREA AROUND YOU
input = []
max_in = 0
for pos in self.area2:
try:
name = self.game.board[pos]
try:
if int(name) > max_in:
max_in = int(name)
except:
pass
nodes = self.name2num_dict[name]
input += nodes
except:
input += [0] * len(self.name2num_dict["0"])
self.input = input
self.max_in = max_in # FIGURE OUT WHAT YOUR TARGET OUTPUT SHOULD BE
# this is not used to determine where to go or what to do
# it is only used durring the learning phase
target = []
for i in range(len(self.area)):
pos = self.area[i]
try:
num = self.game.mine_array[pos]
target.append(num)
except:
target.append(.5)
self.target = target ################################################################
# get output from neural net
################################################################
# uncomment this to play perfectly (cheat)
# for learning examples quicker
if self.cheat:
print "cheating"
output = target
else:
output = self.nn.getOut(input)
self.output = output certainty = sum(output)/float(len(output))
certainty = max(certainty, 1-certainty)
self.certainty[self.pos] = certainty weight = WEIGHT
# update your guesses for whether or not a square has a mine
for i in range(OUTPUT_GRID**2):
try:
if SHARE_MAP:
output[i] = self.game.guess[self.area[i]] * (1-weight) + output[i] * weight
self.game.guess[self.area[i]] = output[i]
else:
output[i] = self.guess[self.area[i]] * (1-weight) + output[i] * weight
self.guess[self.area[i]] = output[i]
except:
pass # this just means we're looking out of bounds def act(self):
if not self.game.FINISHED:
self.old_pos = self.pos
x,y = self.pos
self.getNNOutOf(self.pos)
################################################################
# Q STUFF
################################################################
'''
output = self.output
out_array = []
count = 0
for a in range(OUTPUT_GRID):
out_array.append([])
for b in range(OUTPUT_GRID):
try:
if output[count] < .5: o = 0
elif self.game.board[self.pos] == "f": o = -1
else: o = 1
out_array[a].append(o)
count += 1
except:
out_array[a].append(0)
ahha = False
for s in self.memory:
ahha = s.isMatch(out_array)
if ahha:
state = s
break
if not ahha:
state = State(out_array)
self.memory.append(state) action_i = state.getActionIndex()
action = state.actions[action_i]
''' ################################################################
# EVENT LOOP - if you're drawing the board, check for events
################################################################
if self.human: found = False
if self.game.draw_board:
for i in range(5000):
event = pygame.event.poll() if event.type == QUIT:
self.game.running = False
pygame.quit ()
break elif event.type == KEYDOWN:
if event.key == K_r:
self.switch()
break
if event.key == K_ESCAPE:
self.game.running = False
pygame.quit ()
break
if event.key == K_c:
self.cheat = bool(1 - int(self.cheat))
break
if event.key == K_g:
self.game.goggles = (self.game.goggles + 1) % 3
break # if something is clicked
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
cleared = self.game.dig(self.pos)
found = True
'''
state.reward("L")
state.punish("R")
'''
if event.button == 3:
self.game.mark(self.pos)
found = True
'''
state.reward("R")
state.punish("L")
''' elif event.type == MOUSEMOTION:
self.old_pos = self.pos
self.pos = self.mouse2Grid(event.pos)
x, y = self.pos
a, b = self.old_pos
if self.old_pos != self.pos:
'''
if x > a:
state.reward("E")
state.punish("W")
if x < a:
state.reward("W")
state.punish("E")
if y > a:
state.reward("S")
state.punish("N")
if y < a:
state.reward("N")
state.punish("S")
'''
found = True else:
self.pos = self.mouse2Grid(pygame.mouse.get_pos()) ################################################################
# BOT SPECIFIC STUFF
################################################################
elif not self.human:
found = False
if self.game.draw_board:
for i in range(10):
event = pygame.event.poll()
if event.type == KEYDOWN:
if event.key == K_h:
self.switch()
if event.key == K_c:
self.cheat = bool(1 - int(self.cheat))
break
if event.key == K_g:
self.game.goggles = (self.game.goggles + 1) % 3
break
if event.key == K_ESCAPE:
self.game.running = False
pygame.quit ()
break if event.type == QUIT:
self.game.running = False
pygame.quit ()
break found = True
#self.wholeBoard()
self.threshClick()
self.getCertainty()
self.simMove()
'''
x, y = self.pos if action == "L":
self.game.dig(self.pos)
elif action == "R":
self.game.mark(self.pos)
elif action == "N":
y -= 1
elif action == "E":
x += 1
elif action == "S":
y += 1
elif action == "W":
x -= 1
elif action == "J":
x = random.randint(0, self.game.width - 1)
y = random.randint(0, self.game.height - 1) if x < 0: x = 0
if x > self.game.width: x = self.game.width
if y < 0: y = 0
if y > self.game.height: y = self.game.height
self.pos = x, y
'''
################################################################
# Remember what you've done.
################################################################
if found:
m = [self.input, self.target, self.max_in]
if (random.random() < ALLOW_REPEATS or
m not in self.move_list):
self.move_list.append(m)
#print len(self.move_list)
if len(self.move_list) > MOVES_LEARNED:
#r = random.randint(0, len(self.move_list))
#self.move_list = self.move_list[:r] + self.move_list[r+1:]
self.move_list = self.move_list[1:]
self.num_moves += 1 '''if self.num_moves == MOVES_LEARNED:
print "truncating move list"
if self.num_moves == MAX_MOVES / 20:
print "5%"
if self.num_moves == MAX_MOVES / 4:
print "1/4"
if self.num_moves == MAX_MOVES / 2:
print "half way"''' def getCertainty(self):
############################################################
# how certain are you that you've chosen correctly
############################################################
self.best_guesses = [self.pos]
best = self.pos
lowest_errors = [1]
lowest = 1
global_certainty = 0
local_certainty = 0
for i in range(self.game.width):
for j in range(self.game.height):
if SHARE_MAP:
g = self.game.guess[(i,j)]
else:
g = self.guess[(i,j)]
err = min(g, 1-g) ** 2
global_certainty += 1 - err
if (i,j) in self.area:
local_certainty += 1 - err
if (i,j) in self.closed and random.random() < .9:
continue
if err < max(lowest_errors):
lowest_errors.append(err)
self.best_guesses.append((i,j))
if len(self.best_guesses) > NUM_POS:
self.best_guesses = self.best_guesses[1:]
lowest_errors = lowest_errors[1:]
if err < lowest:
best = (i,j)
lowest = err global_certainty /= float(self.game.width * self.game.height)
local_certainty /= float(self.game.width * self.game.height) def QLearn(self, move, reward, threshold = .05, decay = .7):
# while there's reward and states left
while reward > threshold and move >= 0: # reward the state at 'move', an int
pos = self.move_list[move][0]
input = self.move_list[move][1]
n = max(max(input), 0)
target = self.move_list[move][2] for i in range(n):
self.nn.train(input, target, reward) # then reduce your reward and move to the previous state
move -= 1
reward *= decay def open(self, pos):
if pos in self.closed:
self.closed.remove(pos) def close(self, pos):
if pos not in self.closed:
self.closed.append(pos) def learn(self):
# go through each move and back propogate rewards
index = 0
#avg_num = 0
for index in range(len(self.move_list)):
move = self.move_list[index]
self.nn.train(move[0], move[1],self.alpha, self.beta)
#avg_num += move[2]
#avg_num /= float(len(self.move_list))
self.alpha *= OPEN_MIND
self.beta *= OPEN_MIND
#print avg_num
#print self.alpha, self.beta def reward(self, i, amt):
self.state.rewards[i] += amt def punish(self, i, amt):
self.reward(i, -amt) def setPos(self, pos):
self.pos = pos def getNumMineGuess(self):
sum = 0
if SHARE_MAP:
g = self.game.guess.values()
else:
g = self.guess.values()
for guess in g:
if guess > .5:
sum += 1
return sum
game.py是运行游戏的主循环,处理各种事件
# -*- coding: utf-8 -*-
"""
Created on Sun Oct 7 10:16:24 2018
作者邮件:231469242@qq.com
作者微信公众号:PythonEducation
"""
#
# game.py
#
# Copyright 2010 Nolan Baker <hendersonhasselbalch@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA. TORUS = False
OPEN_FIRST = True# false to be able to lose on first click
decided = False
LOAD_NN = True
while not decided:
try:
i = raw_input("Would you like to forget? (y/n) \n")
if i == "y":
LOAD_NN = False
decided = True
if i == "n":
LOAD_NN = True
decided = True
except:
print("No, that's not quite right")
SAVE_NN = True
SAVE_CSV = True
ASCII_OUTPUT = False
LEARN = True
DRAW = True
RECORD = False # this is really resource intensive
HUMAN = False
CHUNK = 100
SAVE_CHUNK = 1
SAVE_INT = 1
OUTPUT_TEXT = "win_pct,sq_err,pct_cor,cleared,cor_digs,inc_digs,cor_flags,inc_flags\n"
DIFF = 0
DIFF_MINDS = False
AGENTS = 1 import math, os, sys, platform, pickle, random
if DRAW:
import pygame
from pygame.locals import *
from neural_network import *
from agent import *
try:
from numpy import *
import numpy.random as nrand
except:
print "You need numpy! Ahh!"
exit(-1) ########################################################################
# MINESWEEPER
######################################################################## class Game:
def __init__(self, width, height, mines, draw = True, tile_size = 32, torus = False):
self.width = width
self.height = height
self.mines = mines
self.wins = 0
self.loses = 0
self.torus = torus
self.guess = {} self.draw_board = draw
if self.draw_board:
pygame.init()
self.surface = pygame.Surface((width * tile_size, height * tile_size))
self.clock = pygame.time.Clock()
self.tile_size = tile_size
self.tile_dict = {}
names = "_012345678fime"
for name in names:
size = (self.tile_size, self.tile_size)
self.tile_dict[name] = pygame.transform.scale(self.loadImg(name), size) self.reset() def reset(self):
self.goggles = 1
self.FINISHED = False
self.did_change = True
self.left_clicks = 0
self.cleared = 0
self.correct_digs = 0
self.incorrect_digs = 0
self.correct_flags = 0
self.incorrect_flags = 0
self.towel_thrown = 0
self.first_click = True
self.done = False
self.result = -1
for i in range(self.width):
for j in range(self.height):
self.guess[(i,j)] = .5 self.mine_array = {}
for h in range(self.height):
for w in range(self.width):
self.mine_array[(w, h)] = 0 self.pos_li = []
while len(self.pos_li) != self.mines:
rand_x = random.randint(0, self.width)
rand_y = random.randint(0, self.height)
pos = (rand_x, rand_y) if pos not in self.pos_li:
self.pos_li.append(pos) for pos in self.pos_li:
self.mine_array[pos] = 1 self.board = {}
for h in range(self.height):
for w in range(self.width):
self.upTile((w, h), "_") def throwTowel(self):
self.towel_thrown = 1 def loadImg(self, name):
return pygame.image.load(os.path.join("images", name + ".png")) def upTile(self, pos, symbol):
self.did_change = True
self.board[pos] = symbol #draw stuff if drawing turned on
if self.draw_board:
x, y = pos
p = (x * self.tile_size, y * self.tile_size)
self.surface.blit(self.tile_dict[symbol], p) def resize(self, w, h, m):
self.width = w
self.height = h
self.mines = m def printBoard(self):
s = ""
for h in range(self.height):
for w in range(self.width):
try:
s += self.board[(w, h)]
except:
s += "X"
s += "\n"
print s def mark(self, pos):
# place a flag down or pull one up
if self.board[pos] == "_":
self.upTile(pos, "f")
return True elif self.board[pos] == "f":
self.upTile(pos, "_")
return False def dig(self, pos):
cleared = 0
if not self.done and self.board[pos] != "f":
self.left_clicks += 1
"surely dig and clear can be merged"
"things get funky with recursion"
# clear a space and see if you win
cleared = self.clear(pos)
if self.isWon():
self.wins += 1
self.result = 1
self.done = True
if cleared > 0:
self.correct_digs += 1
elif cleared == 0:
self.incorrect_digs += 1
return cleared def clear(self, pos, auto = False):
cleared = 0
x = pos[0]
y = pos[1] # if the space has a mine and it's not your first move
if (self.mine_array[pos] == 1 and
(not self.first_click or not OPEN_FIRST)): # go through every space on the board
for h in range(self.height):
for w in range(self.width): # if the space is empty and flagged
if (self.mine_array[(w, h)] == 0 and
self.board[(w, h)] == "f"): # mark it as incorrectly flagged
self.upTile((w, h), "i")
self.incorrect_flags += 1 # if the space has a mine and is flagged
elif (self.mine_array[(w, h)] == 1 and
self.board[(w, h)] == "f"): # mark it as incorrectly flagged
self.correct_flags += 1 # if the space has a mine and is not flagged
elif (self.mine_array[(w, h)] == 1 and
self.board[(w, h)] == "_"): # mark it as having a mine
self.upTile((w, h), "m") # mark your position as exploded
self.upTile(pos, "e") # # end the game
self.loses += 1
self.done = True # if it's your first click
if self.first_click and OPEN_FIRST:
self.first_click = False
if self.torus:
w = self.width
h = self.height
area = [((x-1)%w, (y-1)%h), (x, (y-1)%h), ((x+1)%w, (y-1)%h),
((x-1)%w, y) , (x, y) , ((x+1)%w, y) ,
((x-1)%w, (y+1)%h), (x, (y+1)%h), ((x+1)%w, (y+1)%h)]
else:
area = [(x-1, y-1), (x, y-1), (x+1, y-1),
(x-1, y), (x, y), (x+1, y),
(x-1, y+1), (x, y+1), (x+1, y+1)]
count = 0
for s in area:
try:
count += self.mine_array[s]
self.mine_array[s] = 0
except:
pass rh = random.randint(0, self.height - 1)
rw = random.randint(0, self.width - 1)
for h in range(self.height):
for w in range(self.width):
p = ((w + rw) % self.width, (h + rh) % self.height)
if self.mine_array[p] == 0 and p not in area:
if count > 0:
self.mine_array[p] = 1
count -= 1
else:
break # if the space is empty
if self.mine_array[pos] == 0: # get your neighbors
if self.torus:
w = self.width
h = self.height
area = [((x-1)%w, (y-1)%h), (x, (y-1)%h), ((x+1)%w, (y-1)%h),
((x-1)%w, y) , (x, y) , ((x+1)%w, y) ,
((x-1)%w, (y+1)%h), (x, (y+1)%h), ((x+1)%w, (y+1)%h)]
else:
area = [(x-1, y-1), (x, y-1), (x+1, y-1),
(x-1, y), (x, y), (x+1, y),
(x-1, y+1), (x, y+1), (x+1, y+1)] # if the space is unknown
if self.board[pos] == "_":
cleared += 1 # check all neighbors for mines
mines = 0
for s in area:
try:
mines += self.mine_array[s]
except:
pass # invalid position # set your image to the number of adj. mines
self.upTile(pos, str(mines)) # if the space is numbered
if self.board[pos] in "012345678": # check all neighbors for flags
flags = 0
for s in area:
try:
if self.board[s] == "f":
flags += 1
except:
pass # invalid position # if the number of flags is your number
if ((flags == int(self.board[pos]) and not auto) or
int(self.board[pos]) == 0): # clear all of the unknown spaces around you
for s in area:
try:
if self.board[s] == "_":
cleared += self.clear(s, True)
except:
pass # invalid position return cleared def isWon(self):
cleared = 0
covered = 0
for w in range(self.width):
for h in range(self.height):
if (self.board[(w,h)] != "_" and
self.board[(w,h)] != "f" and
self.mine_array[(w,h)] == 0):
cleared += 1
if (self.board[(w,h)] == "_" or
self.board[(w,h)] == "f" and
self.mine_array[(w,h)] == 1):
covered += 1
self.cleared = cleared
if (cleared == ((self.width * self.height) - self.mines) and
covered == self.mines):
self.FINISHED = True
return True
self.FINISHED = False
return False def getErrors(self):
sq_err = 0
correct = 0
for x in range(self.width):
for y in range(self.height):
err = abs(self.mine_array[(x,y)] - self.guess[(x,y)])
sq_err += err ** 2
if err < .5: correct += 1
sq_err /= float(self.width * self.height)
correct /= float(self.width * self.height)
return sq_err, correct ################################################################################
# example
################################################################################ def randomGame():
game = Game(4,4,3)
while 1:
game.reset()
while not game.done:
c = random.randint(0,1)
x = random.randint(0, game.width - 1)
y = random.randint(0, game.height - 1)
if c == 0:
game.dig((x,y))
elif c == 1:
game.mark((x,y))
w, l = game.wins, game.loses
print w,"w",l,"l",(w*100.0)/(w+l),"%"
try: input()
except: pass def main():
if DIFF == 0:
#print "SMALL - 8x8 w/ 10 mines"
w = 8
h = 8
m = 10
t = 64
if DIFF == 1:
#print "MEDIUM - 16x16 w/ 40 mines"
w = 16
h = 16
m = 40
t = 32
if DIFF == 2:
#print "LARGE - 32x16 w/ 99 mines"
w = 32
h = 16
m = 99
t = 26
if DIFF == 3:
w = 8
h = 8
m = 15
t = 32
s = "" # create your game board
if DRAW: os.environ['SDL_VIDEO_CENTERED'] = '1'
game = Game(w, h, m, draw = DRAW, tile_size = t, torus = TORUS)
count = 0
frame = 0
banner = "W:0 - L:0"
if DRAW:
pygame.display.set_caption(banner)
screen = pygame.display.set_mode((w * t, h * t)) # create your players
alist = []
for i in range(AGENTS):
alist.append(Agent(game))
#agent.cheat = True
if HUMAN:
alist[0].switch() ####################################################################
# load your saved neural net from a file
####################################################################
if LOAD_NN:
if DIFF_MINDS:
for i in range(len(alist)):
try:
f = open(os.path.join("data","nn" + str(i) + ".obj"), "r")
alist[i].nn = pickle.load(f)
print "Loading Agent " + str(i) + "'s neural network."
f.close()
except:
try:
f = open(os.path.join("data","nn.obj"), "r")
alist[i].nn = pickle.load(f)
for agent in alist:
agent.nn = alist[i].nn
print "Loading stock neural network."
f.close()
except:
#print sys.exc_info()
print "Couldn't load mind. Creating one."
else:
try:
f = open(os.path.join("data","nn.obj"), "r")
alist[0].nn = pickle.load(f)
for agent in alist:
agent.nn = alist[0].nn
print "Loading neural network."
f.close()
except:
#print sys.exc_info()
print "Couldn't load mind. Creating one." ####################################################################
# create a log file
####################################################################
if SAVE_CSV:
csv = open(os.path.join("data", str(count) + ".csv"), "w")
csv.write(OUTPUT_TEXT) # get things started
game.running = True
while game.running:
for agent in alist:
agent.clearMoves() ################################################################
# AN INDIVIDUAL GAME
################################################################
while not game.done:
for agent in alist:
agent.act()
if ASCII_OUTPUT:
sq_err, correct = game.getErrors()
clear = "clear"
if platform.system() == "Windows":
clear = "cls"
os.system(clear)
print(banner)
print("Squared Error", sq_err)
print("Percent Correct", correct)
game.printBoard() if game.draw_board:
game.clock.tick()#60) #to pace the bot
for event in pygame.event.get() :
if event.type == QUIT:
game.running = False
pygame.quit () # if the keyboard is used
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
game.running = False
pygame.quit ()
if ((event.key == K_r and alist[0].human) or
(event.key == K_h and not alist[0].human)):
alist[0].switch()
if event.key == K_c:
alist[0].cheat = bool(1 - int(alist[0].cheat))
if event.key == K_g:
game.goggles = (game.goggles + 1) % 3 if game.goggles == 0 or game.goggles == 1:
screen.blit(game.surface, (0,0)) # DRAW AGENT'S GUESS
# purple = mine, yellow = not mine
# transparent = certain, opaque = not sure
if game.goggles == 1 or game.goggles == 2:
temp = pygame.Surface((w,h))
tran = pygame.Surface((t-1, t-1))
for i in range(w):
for j in range(h):
g = 1 - game.guess[(i,j)]
g *= 255
tran.fill((160,g,255-g))
g = int(min(g, 255-g) * 2)
tran.set_alpha(int(g / 1.4))
screen.blit(tran, (i * t + 1, j * t + 1)) ########################################################
# DRAW EACH AGENT
########################################################
for agent in alist:
x, y = agent.pos
rx, ry = random.randint(-t/3,t/3), random.randint(-t/3,t/3)
X, Y = x * t + t/2.0 + rx, y * t + t/2.0 + ry
pygame.draw.circle(screen, (0,0,0), (int(X),int(Y)), 3) ########################################################
# MAKE A MOVIE
########################################################
if RECORD and game.did_change:
print "recording"
old_board = copy(game.board)
pygame.image.save(screen, os.path.join("video", str(frame) + ".png"))
frame += 1
pygame.display.flip()
game.did_change = False ################################################################
# compare agent's map of minefield to actual
################################################################
sq_err, correct = game.getErrors() ################################################################
# print results to file
################################################################
win, lose = game.wins, game.loses
try:
win_pct = (win*100.0)/(win+lose)
except: win_pct = 0 s = (str(win_pct) + "," +
str(sq_err) + "," +
str(correct) + "," +
str(game.cleared) + "," +
str(game.correct_digs) + "," +
str(game.incorrect_digs) + "," +
str(game.correct_flags) + "," +
str(game.incorrect_flags) + "\n")
if SAVE_CSV: csv.write(s) banner = "W: " + str(win) + " - L: " + str(lose)
if DRAW: pygame.display.set_caption(banner)
#print "W: ", win, " - L: ", lose
print s ################################################################
# START NEW FILE AFTER chunk ITTERATIONS
################################################################
count += 1
if SAVE_CSV and count % CHUNK == 0:
csv.close()
csv = open(os.path.join("data", str(count) + ".csv"), "w")
csv.write(OUTPUT_TEXT)
elif SAVE_CSV and not game.running:
csv.close() ################################################################
# LEARN!!!
################################################################
if LEARN:
if DIFF_MINDS:
for agent in alist:
agent.learn()
else:
nn = alist[0].nn
for agent in alist:
agent.nn = nn
agent.learn()
nn = agent.nn
for agent in alist:
agent.nn = nn
agent.memory = alist[0].memory ################################################################
# SAVE NN
################################################################
if SAVE_NN and count % SAVE_INT == 0:
if DIFF_MINDS:
for i in range(len(alist)):
if i % SAVE_CHUNK == count % SAVE_CHUNK:
try:
f = open(os.path.join("data","nn" + str(i) + ".obj"), "w")
pickle.dump(alist[i].nn, f)
print "Saving neural network number " + str(i) + "."
f.close()
except:
#pass
print "Couldn't save your neural network."
else:
try:
f = open(os.path.join("data","nn.obj"), "w")
pickle.dump(alist[0].nn, f)
print "Saving your neural network."
f.close()
except:
#pass
print "Couldn't save your neural network." ################################################################
# RESET BOARD
################################################################
game.reset() if __name__ == '__main__':
main()
我们运行程序,看到下图扫雷游戏,键盘c按键是用于作弊的,就是调用代理人
运行环境是Python2.7, anaconda
好了,就讲解到这里,游戏编程更多内容请观看我在网易云的视频教程Python菜鸟快乐游戏编程_pygame:
https://study.163.com/course/courseMain.htm?courseId=1006188025&share=2&shareId=400000000398149
我的网易云教程提供了编译好脚本,大家可以下载直接调用,边观看边演练。视频采用专业显卡录制,2k超高清,朋友们可以看清楚每一行代码的字母。
have fun!
Python入门经典(2K分辨率超清,免费,博主录制)
https://study.163.com/course/courseMain.htm?courseId=1006183019&share=2&shareId=400000000398149