#! /usr/bin/python -O # -*- coding: iso-8859-15 -*- # # A simple Awalé game. # Copyright (C) 2007 MiKael NAVARRO # # 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """A simple Awalé game. Copyright (C) 2007 MiKael NAVARRO The count-and-capture official board game of Africa. Test free awale software against pyAwale engine (http://www.nongnu.org/awale/). """ # Specific variables for pydoc __author__ = "MiKael Navarro " # Include directives import sys import os import re import time import datetime import subprocess HAVE_PSYCO = True try: # Psyco optim import psyco psyco.profile(0.2) except: HAVE_PSYCO = False if __debug__: from pprint import pprint as pp # Path to awale module lib_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../src/") sys.path.append(lib_path) import awale # Re-use some functions from pyawale script from pyawale import human_sow as freeawale_sow from pyawale import computer_sow as pyawale_sow from pyawale import display from pyawale import Tee # Global variables FREE_AWALE_EXPECTED_MOTIF = r"board=(.*) score=(\d+-\d+) move=(\d+) (RUN|END|ERR)" # # Run pyAwale engine.. # def test_freeawale(algo, level, depth, begin, freeawale_program): """Test free awale software against pyAwale engine.""" # Main pyAwale board awale_board = awale.Awale(board=[awale.INITIAL_SEEDS]*awale.BOARD_SIZE, score=[0, 0], algo=algo, depth=level*3) # Launch free awale in engine mode & single move (computer= south player) cmd = freeawale_program + " --depth %s --xawale --single --board=%s --score=%s --computer 1" title = "Free Awale (depth=%d) vs/ pyAwale (algo='%s', level=%d)" % (depth, awale_board.algo_type, awale_board.algo_depth/3) display(awale_board, title) turn = 0 label = "RUN" while label == "RUN": try: if begin: # Launch free awale with current board/score print "Free Awale sown ...", board = '-'.join(map(str, awale_board.board)) score = '-'.join(map(str, awale_board.score)) start_time = time.time() child = subprocess.Popen(cmd % (depth, board, score), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) child_stdout, child_stderr = child.stdout, child.stderr #child.wait() output = child_stdout.readline() elapsed_time = time.time() - start_time err = child_stderr.readline() try: # Parse free awale output match = re.search(FREE_AWALE_EXPECTED_MOTIF, output) board = match.group(1).split('-') score = match.group(2).split('-') move = int(match.group(3)) - 1 # free awale cups begin at 1 label = match.group(4) except: #print "output=", output #print "err=", err break # nou free awale output? eog? # Apply result on Awale board print "\r", freeawale_sow(awale_board, awale.SOUTH_PLAYER, awale.HUMAN_CUPS[move], elapsed_time) turn = turn + 1 # count free awale turn else: begin=True # ok, next time # Now compute pyAwale best sown pyawale_sow(awale_board, awale.NORTH_PLAYER) turn = turn + 1 # count turn except awale.InvalidSown, msg: # invalid input #warnings.warn(str(msg), stacklevel=1) print >> sys.stderr, msg except awale.NoMoreMove, msg: # no more seeds if __debug__: print >> sys.stderr, msg break except awale.EndOfGame, msg: # eog if __debug__: print >> sys.stderr, msg break print "Result (%d turns)" % turn print awale_board south_score, north_score = awale_board.score # final score # Comptabilize seeds left on board south_score += sum( [awale_board.board[idx] for idx in awale.PLAYER_CUPS[awale.SOUTH_PLAYER] ] ) north_score += sum( [awale_board.board[idx] for idx in awale.PLAYER_CUPS[awale.NORTH_PLAYER] ] ) if south_score > north_score: print "Free Awale wins (%d seeds vs %d)." % (south_score, north_score) elif north_score > south_score: print "pyAwale wins (%d seeds vs %d)." % (north_score, south_score) else: print "Draw (%d seeds each)." % south_score # # Start free awale in interactive mode. # def test_freeawale_interactive(algo, level): """Test pyAwale engine against free awale software.""" import pexpect # http://pexpect.sourceforge.net/ # Main pyAwale board awale_board = awale.Awale(algo=algo, depth=level*3) # Launch free awale in engine mode & single move (south player) cmd = FREE_AWALE_PATH + " --xawale --computer 1" print "Free Awale vs/ pyAwale (algo='%s', level=%d)" % (awale_board.algo_type, awale_board.algo_depth/3) print awale_board child = pexpect.spawn(cmd) while True: # Compute free awale result #child.expect(".*RUN.*") child.expect(expected_motif) print "Expect '", child.after.strip(), "'" match = re.search(expected_motif, child.after.strip()) board = match.group(1).split('-') score = match.group(2).split('-') move = match.group(3) label = match.group(4) print "Free awale sown from", move #print board, score awale.board = board awale.score = score print awale_board # Compute my best sown idx = awale_board.best_sown(awale.NORTH_PLAYER) print "pyAwale sown from", idx child.sendline(str(idx)) print "After sendline '", child.after.strip(), "'" awale_board.sow_and_capture(idx) print awale_board child.expect(expected_motif) print "After expect '", child.after.strip(), "'" print "Result" print awale_board # # Main entry point. # def main(options): """Test free awale software against pyAwale engine.""" for run in range(int(options.runs)): if options.log: # redirect stdout to log file curr_date = datetime.datetime.today().isoformat() log_name = "freeawale_vs_pyawale_%s_l%s-%s.log" % (options.algo, options.level, curr_date) log_file = open(log_name, 'w') stdout = sys.stdout sys.stdout = Tee(sys.stdout, log_file) # print to stdout and to a log file # Test free awale software against pyAwale engine test_freeawale(options.algo, int(options.level), int(options.depth), options.begin, options.program) # Test pyAwale engine against free awale software #test_freeawale_interactive(options.algo, int(options.level)) if options.log: # restore stdout sys.stdout = stdout # # External entry point. # if __name__ == "__main__": # Get options from optparse import OptionParser, make_option option_list = [ make_option("-a", "--algo", action="store", dest="algo", type="choice", choices=awale.ALGO_TYPES, default='minimax', help="choose pyAwale ALGO=bfs, minimax, maxi, negamax or alphabeta (default ALGO=%default)"), make_option("-l", "--level", action="store", dest="level", default=1, help="difficulty LEVEL=1, 2 or 3 of pyAwale (default LEVEL=%default)"), make_option("-d", "--depth", action="store", dest="depth", default=7, help="depth of free awale algorithm (default DEPTH=%default)"), make_option("-b", "--begin", action="store_true", dest="begin", default=False, help="free awale begins (default BEGIN=%default)"), make_option("-o", "--log", action="store_true", dest="log", default=False, help="output results in log file (default LOG=%default)"), make_option("-r", "--run", action="store", dest="runs", default=1, help="nb tries (default RUNS=%default)"), make_option("-p", "--program", action="store", dest="program", default="/usr/local/bin/awale", help="path to free awale program (default PROGRAM=%default)"), ] parser = OptionParser(usage="python -O %prog [options] ... [args] ...", description="Test free awale software against pyAwale engine.", option_list=option_list) (options, args) = parser.parse_args() # Process start here main(options)