2008年8月17日星期日

井字過三關

今次寫這個井字過三關Program花了不少時間
用python+gtk寫的,可以和電腦對戰
不過電腦比較低能,很容易就能贏它
準備加入聯網對戰功能,雖然井字過三關對戰好像很白痴
………………………………
#! /usr/bin/env python
# -*- coding:UTF-8 -*-

# This is a simple XO game - tic tac toe
# Written by RAh-XePhON @ http://ToKyo-JuPiTer.Blogspot.com
# Version 1.0 @ 080719

import pygtk, gtk, gtk.glade
import pdb

### the glade XML resource
XML = '''<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Sun Aug 17 14:58:58 2008 -->
<glade-interface>
<widget class="GtkWindow" id="window">
<property name="width_request">308</property>
<property name="height_request">364</property>
<property name="border_width">2</property>
<property name="resizable">False</property>
<property name="window_position">GTK_WIN_POS_CENTER</property>
<signal name="destroy" handler="destroy"/>
<signal name="delete_event" handler="delete_event"/>
<child>
<widget class="GtkFixed" id="fixed1">
<property name="visible">True</property>
<child>
<widget class="GtkMenuBar" id="menubar1">
<property name="width_request">308</property>
<property name="height_request">30</property>
<property name="visible">True</property>
<child>
<widget class="GtkMenuItem" id="menuitem1">
<property name="visible">True</property>
<property name="label" translatable="yes">檔案(_F)</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu1">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="imagemenuitem1">
<property name="visible">True</property>
<property name="label" translatable="yes">新游戲(_N)</property>
<property name="use_underline">True</property>
<signal name="activate" handler="new_game"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image1">
<property name="stock">gtk-new</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="imagemenuitem5">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-quit</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="destroy"/>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="menuitem3">
<property name="visible">True</property>
<property name="label" translatable="yes">設定(_V)</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu2">
<property name="visible">True</property>
<child>
<widget class="GtkCheckMenuItem" id="menuitem2">
<property name="visible">True</property>
<property name="label" translatable="yes">電腦先行</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="comFirst"/>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="menuitem4">
<property name="visible">True</property>
<property name="label" translatable="yes">求助(_H)</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu3">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="imagemenuitem10">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-about</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkStatusbar" id="statusbar1">
<property name="width_request">308</property>
<property name="height_request">30</property>
<property name="visible">True</property>
<property name="spacing">2</property>
</widget>
<packing>
<property name="y">334</property>
</packing>
</child>
<child>
<widget class="GtkFixed" id="map">
<property name="width_request">308</property>
<property name="height_request">304</property>
<property name="visible">True</property>
</widget>
<packing>
<property name="y">30</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>'''

class Chess:
"""a chess"""
b = None # the corresponding button of the chess
p = "" # The Chess Value, this game should be cross or circle.

class Map:
"""this is the class to imitate chessboard and chess"""
com_first = True

def _chess(self):
"""get a new chess and save it into self.chess"""
if self.chess == 'X':
self.chess = 'O'
else:
self.chess = 'X'

def create_chessboard(self):
"""create an empty chessboard"""
print ">>>>>Start a NEW game~"
self._board = [] # the chessboard data
self.chess = ' ' # the player's chess
self.Winner = "" # the winner in this game
self.puts = 0 # count how many steps already put
for i in range(3):
l = []
for j in range(3):
l.append(Chess()) # create a column
self._board.append(l) # append whole column

def set_chess(self, x, y, chess):
"""set the position of chessboard to a particular chess"""
self._board[x][y].p = chess

def map_chess(self, x, y, P=None):
"""map the position of the chess to the corresponding object, or return the object in chessboard"""
if P:
self._board[x][y].b = P
else:
return self._board[x][y].b

def display(self):
"""print out the chessboard"""
for i in self._board:
print "|",
for j in i:
print j.p.ljust(1),
print "|"

def Put(self, position):
"""put a chess on a position"""
x = position[0]
y = position[1]
if not self._board[x][y].p:
self._chess() # get a new chess
self._board[x][y].p = self.chess
if self.Win():
print "Someone has already WIN!"
self.display()
self.puts += 1
return True
else:
return False

def Win(self):
"""check who win in this game
there has eight possible situation
00 01 02
10 11 12
20 21 22
00 10 20
01 11 21
02 12 22
00 11 22
02 11 20"""
x = y = 1
if self._board[x][y].p == self._board[x+1][y-1].p == self._board[x-1][y+1].p and self._board[x][y].p:
self.Winner = self._board[x][y].p
return True
elif self._board[x][y].p == self._board[x-1][y-1].p == self._board[x+1][y+1].p and self._board[x][y].p:
self.Winner = self._board[x][y].p
return True
x = y = 0
for i in range(3):
if self._board[x][y].p == self._board[x][y+1].p == self._board[x][y+2].p and self._board[x][y].p:
self.Winner = self._board[x][y].p
return True
elif self._board[y][x].p == self._board[y+1][x].p == self._board[y+2][x].p and self._board[y][x].p:
self.Winner = self._board[y][x].p
return True
x += 1
return False

class Computer(Map):
"""This class is imitate player think and put the chess by computer """
_board_in = [] # the chess board in computer's mind
com_chess = [] # the chess which computer should be put

def create_chessboard(self):
"""create a new chessboard"""
Map.create_chessboard(self)
if (self.com_first):
Map.Put(self, [1, 1])

def _display(self):
for i in self._board_in:
print "|",
for j in i:
print j.ljust(1),
print "|"

def Put(self, position):
"""reload Put function, let computer put the chess"""
# spectial for the GUI
if Map.Put(self, position):
# check play has already win or not
self.com_chess = []
if not self.Winner:
# analyzing that which position should be put a chess
self.com_chess = self.canPut()
self.player_win() # check that player will win in the next step
self.com_win() # check that computer will win in the next step
if self.com_chess:
Map.Put(self, self.com_chess)
return True
else:
return False

def player_win(self):
"""check is play will win in next round, if yes computer should avoid it"""
found = False
for i in range(3):
for j in range(3):
self._cp_board() # first copy the chessboard into computer's mind
pos = self.check_win("O", i, j) # and then check win to get the position which should be put
if not found and pos:
found = True
print "Found a possible put"
self._display()
print "%d, %d -----------------------------" % (i, j)
self.com_chess = [i, j]

def com_win(self):
"""check is play will win in next round, if yes computer should avoid it"""
found = False
for i in range(3):
for j in range(3):
self._cp_board() # first copy the chessboard into computer's mind
pos = self.check_win("X", i, j) # and then check win to get the position which should be put
if not found and pos:
found = True
print "Found a possible win put"
self._display()
print "%d, %d -----------------------------" % (i, j)
self.com_chess = [i, j]

def check_win(self, chess, i, j):
"""put a chess in the chessboard which in computer's mind and then check it will win or not"""
if not self._board_in[i][j]:
self._board_in[i][j] = chess
x = y = 1
if self._board_in[x][y] == chess and self._board_in[x][y] == self._board_in[x+1][y-1] == self._board_in[x-1][y+1]:
return [i,j]
elif self._board_in[x][y] == chess and self._board_in[x][y] == self._board_in[x-1][y-1] == self._board_in[x+1][y+1]:
return [i,j]
x = y = 0
for i in range(3):
if self._board_in[x][y] == chess and self._board_in[x][y] == self._board_in[x][y+1] == self._board_in[x][y+2]:
return [i,j]
elif self._board_in[y][x] == chess and self._board_in[y][x] == self._board_in[y+1][x] == self._board_in[y+2][x]:
return [i,j]
x += 1
return []
else:
return []

def canPut(self):
"""This function can found out one possible which can be put a chess on it"""
pp = [] # the possible position
self._cp_board() # copy the chessboard into computer's mind
for i in range(3):
for j in range(3):
if not pp and not self._board_in[i][j]:
pp = [i, j]
return pp

def _cp_board(self):
"""copy the chessboard into computer's mind"""
self._board_in = []
for i in range(3):
l = []
for j in range(3):
l.append( self._board[i][j].p )
self._board_in.append(l)


class GUI(Computer):
"""this class for the GUI"""
def __init__(self):
"""initialize"""
self.resource = gtk.glade.xml_new_from_buffer(XML, len(XML)) # create the window from glade resource
self.window = self.resource.get_widget('window')
self.chessboard = self.resource.get_widget('map')
self.signal = {'destroy':self.destroy, 'delete_event':self.delete_event, 'new_game':self.create_chessboard, 'comFirst':self.set_com}
self.resource.signal_autoconnect(self.signal) # connect the signal

self.create_chessboard() # create the chessboard

def show(self):
"""show the window"""
self.window.show() # show the window
gtk.main() # start gtk loop

def delete_event(self, widget, event, data=None):
"""handle the delete event"""
return False

def destroy(self, widget, data=None):
"""handle the close action"""
gtk.main_quit() # close the window and exit the program

def set_com(self, widget, data=None):
"""set computer put chess first or user first"""
if self.com_first:
self.com_first = False
else:
self.com_first = True
self.create_chessboard()

def create_chessboard(self, widget=None, data=None):
"""this function can create the chessboard"""
Computer.create_chessboard(self)
x = y = 0
for i in range(3):
for j in range(3):
Tbutton = gtk.Button()
Tbutton.set_size_request(100, 100)
Tbutton.connect("clicked", self.Put, [i, j])
Tbutton.show()
self.map_chess(i, j, Tbutton)
self.chessboard.put(Tbutton, x, y)
x += 102
x = 0
y += 102

if (self.com_first):
# the first setp of computer, put the cross in the center
Tbutton = self.map_chess(1, 1)
Tbutton.set_label(self.chess)

def Put(self, widget, data=None):
"""to imitate player put a corss or circle in chessboard"""
if Computer.Put(self, data):
if self.com_first:
chess = 'O'
else:
chess = 'X'
widget.set_label(chess) # set the text which should be show on the button, cross or circle
# now is computer's turn
print "Computer: ", self.com_chess
if self.com_chess:
self.set_chess(self.com_chess[0], self.com_chess[1], self.chess)
Tbutton = self.map_chess(self.com_chess[0], self.com_chess[1])
Tbutton.set_label(self.chess)
if self.Winner:
dialog = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "%s Win!" % self.Winner)
if dialog.run():
dialog.destroy()
self.create_chessboard()
if self.puts == 9:
dialog = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "NO one Win!")
if dialog.run():
dialog.destroy()
self.create_chessboard()


if __name__ == "__main__":
main = GUI()
main.show()
發佈留言

熱門文章