예제 #1
0
def _create_playField(x=6, y=7):
    """
    Creates a 2D matrix of zeros. Default size is 6X7

    :param x: int: X axis size
    :param y: int: Y axis Size
    :return: 2D int array
    """
    log.debug("Generating playfield with dimensions [{}][{}]".format(x, y))
    playField = np.zeros(
        (x,
         y))  # uses numpy to create a 2d array of pure zeros (im being lazy)
    return playField
예제 #2
0
def _get_next_open_row(playField, col):
    """
    Checks where the piece will land on this row

    :param playField: The play field
    :param col: The target column
    :return: int representing the row number
    """
    # Iterates through the rows finding the first row where there is no existing piece
    for i in range(ROW_COUNT):
        if playField[i][col] == 0:
            log.debug("Selected row {} for {}".format(i, col))
            return i
    return -1  # negative 1 = no space
예제 #3
0
def exportPlay(column):
    """
    Converts play to an array and exports this data to a text file
    :param column: The players move
    :return:
    """

    global GatherMove
    GatherMove = False  # Ensures that only plays after exported boards are recorded

    dataForExport = []  # Prepare a list for the data to be dumped into
    """
    #Intended AI output would be list of probabilities indicating best move
    #e.g: [0.1, 0.3, 0.5, 0.7, 0.5, 0.2, 0.1]
    #Would indicate best move to be 4th column
    """

    for i in range(0, 7):
        if column == i:
            dataForExport.append(
                1.0)  #For move at col 2 would result in [0,0,1,0,0,0,0]
        else:
            dataForExport.append(0.0)

    # EXPORTING CODE #
    if not os.path.isdir("trainingData"):
        # Verify the desired folder exists, if not, create it
        log.debug("Training Data folder missing... creating")
        os.mkdir("trainingData")

    fileNum = 0
    try:
        while True:
            # this loop makes sure it wont overwrite an existing file, then writes
            filename = "trainingData/ExportedMove{}.txt".format(fileNum)
            if os.path.isfile(filename):
                fileNum += 1
            else:
                f = open(filename, "w")
                f.write(str(dataForExport))
                f.close()
                log.info("Exported current state to {}".format(filename))
                return True
    except Exception as e:
        # Error handling ^-^
        log.error("Failed to export game state: {}".format(e))
        return False
예제 #4
0
def _input(playField, turn, pos):
    """
    Gets the player's move and validate it

    param playField: the play field
    :param turn: the current turn
    :return: the column the player chose
    """
    # If AI is enabled, this if statement will call ai to give a column number
    if TestMode:
        if AIMode and (turn % 2 == 0):
            return _get_AI_move(playField)
        return random.randint(0, ROW_COUNT)
    if turn % 2 == 0 and AIMode:
        log.debug("Polling AI code for its move...")
        col = _get_AI_move(playField)
        """
        # todo: call some function that'll return a column number
        col = 0 # todo: remove this line
        return  # todo: remove this line and uncomment and edit the line below
        col = ["some function to get a value off the AI"]
        """

        ### SANITY CHECKS ###
        if col is None:
            log.critical("AI returned Null value")
            _quit(1)  # exit with an error condition
        try:
            int(col)
        except ValueError:
            log.critical("AI didnt return an int")
            _quit(1)  # exit with an error condition
        if col > COLUMN_COUNT - 1:
            log.critical("AI returned an impossible position")
            _quit(1)  # exit with an error condition
        else:
            # value from the AI should be known good now, it can be used safely
            log.debug("AI is putting its piece on column {}".format(col))
            return col

    else:
        # if AIMode is not enabled, or its player 1, take input
        if turn % 2 == 0 and DataGatherMode:
            col = random.sample([0, 1, 2, 3, 4, 5, 6], 1)
            while not _validate_move(playField, col):
                col = random.sample([0, 1, 2, 3, 4, 5, 6], 1)
            log.debug("Randomiser clicked at {}|{} = column: {}".format(
                pos[0], pos[1], col))
        else:
            posx = pos[0]
            col = int(math.floor(posx / 100))
            if col > COLUMN_COUNT - 1:
                return None
            log.debug("Player clicked at {}|{} = column: {}".format(
                pos[0], pos[1], col))
        return col
def _fit_model(epochs):

    # try:
    #     global model
    #     global training_input
    #     global training_output
    #
    #     log.info('Fitting model')
    #
    #     model.fit(training_input, training_output, epochs=epochs)    #Not currently working
    #
    #
    #     log.info('\tModel fitted\n')
    #     return True
    #
    # except:
    #     log.error('\tUnknown error in NeuralNetwork._fit_model\n')
    #     return False

    # global model
    # global training_input
    # global training_output
    #
    # # print(model.summary())
    #
    # log.info('Fitting model')
    # model.fit(training_input, training_output, epochs=epochs)    # Not currently working
    #
    #
    # log.info('\tModel fitted\n')
    try:
        log.info('Fitting model')
        global model
        model.fit(training_input,
                  training_output,
                  epochs=epochs,
                  batch_size=128)  # Trains neural network

        log.debug("\tModel fitted\n")
        return True
    except:
        log.error("\tFailed to fit model\n")

        return False
예제 #6
0
def _drop_piece(playField, row, col, player):
    """
    Places the piece onto the playField

    :param playField: The play field
    :param row: The target row
    :param col: The target column
    :param player: The player making the move
    :return: None
    """
    try:
        log.debug("P{}: Placing piece at [{}][{}]".format(player, row, col))
        playField[row][col] = player

        if GatherMove:  # Exports play if board exported
            exportPlay(col)
    except Exception as e:
        log.error("Failed to place piece: {}".format(e))
        return False
예제 #7
0
def flattenAndExport(playfield):
    """
    Flattens the 2D array into a 1D array and exports this data to a text file
    :param playfield: The game's playfield
    :return:
    """

    global GatherMove
    GatherMove = True  # The play made at this point to be recorded, for AI target data

    dataForExport = []  # Prepare a list for the data to be dumped into
    for row in playfield:
        for item in row:
            dataForExport.append(
                item)  # dump each item one by one into this new list

    # EXPORTING CODE #
    if not os.path.isdir("trainingData"):
        # Verify the desired folder exists, if not, create it
        log.debug("Training Data folder missing... creating")
        os.mkdir("trainingData")

    fileNum = 0
    try:
        while True:
            # this loop makes sure it wont overwrite an existing file, then writes
            filename = "trainingData/ExportedState{}.txt".format(fileNum)
            if os.path.isfile(filename):
                fileNum += 1
            else:
                f = open(filename, "w")
                f.write(str(dataForExport))
                f.close()
                log.info("Exported current state to {}".format(filename))
                return True
    except Exception as e:
        # Error handling ^-^
        log.error("Failed to export game state: {}".format(e))
        return False
Version: 0.01
Purpose: Creates/Saves/Loads neural network for Connect-Four game
Author: Graham Mark Broadbent
Date: 12/03/19
"""

import logging
from logManager import log

log.info('Program Begin\n')

import DataFormatter as df  # Because I couldn't find an easier option, I made one

log.info('Importing Packages')
import os
log.debug('\tImported OS')
import tensorflow as tf
log.debug('\tImported TensorFlow')  # TensorFlow 1.5
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
log.debug('\tImported Keras')
import numpy as np
log.debug('\tImported Numpy')
log.info('\tImporting Done\n')

training_input = []
training_output = []
model = None
new_model = None
has_model = False
예제 #9
0
def _game_loop(playField):
    """
    The main game loop
    
    :param playField: the play field
    :return: 
    """
    global TestMode
    global DataGatherMode
    global AIMode
    global AI
    global turn
    global hueHSV

    log.info("Game Loop started")
    turn = 1
    while True:
        # BIG SCARY EVENT LOOP!

        for event in pygame.event.get():  # poll pygame for events
            if event.type == pygame.QUIT:
                # Allow game to quit
                _quit()
            if not TestMode:

                if event.type == pygame.MOUSEMOTION:
                    # User moved the mouse, so move their piece after their cursor for  A E S T H E T I C S
                    pygame.draw.rect(
                        screen, (0, 0, 0), (0, 0, width, 100)
                    )  # hide the last frame of motion, turn this off for some really trippy stuff
                    posx = event.pos[0]  # get the location of the cursor
                    if posx < (
                            COLUMN_COUNT * 100
                    ) - 25 and posx > 25:  # messy way of clamping the location above the game columns
                        if turn % 2 == 0:  # determine whos turn it is, and make the piece that colour
                            pygame.draw.circle(screen, (206, 22, 48),
                                               (posx, 50), int(radius))
                        else:
                            pygame.draw.circle(screen, (255, 201, 23),
                                               (posx, 50), int(radius))
                        pygame.display.update()  # refresh the screen
                if event.type == pygame.MOUSEBUTTONDOWN or turn % 2 == 0 and AIMode:
                    # click = drop piece
                    if turn % 2 == 0 and AIMode:
                        col = _input(playField, turn, pos=[0, 0])
                    else:
                        col = _input(
                            playField, turn, event.pos
                        )  # determine what column the user clicked above
                    if col is not None:  # None = the user didnt click in a valid location, so we ignore it
                        row = _get_next_open_row(
                            playField,
                            col)  # determine what row we should place a piece
                        if row != -1:
                            _drop_piece(playField, row, col,
                                        turn % 2 + 1)  # drop said piece

                            if _winning_move(playField, turn % 2 +
                                             1):  # check if a player has won
                                log.info(
                                    "Win condition met for player {}".format(
                                        turn % 2 + 1))
                                renderer(playField)
                                print("Player {} is the Winner in {} turns!".
                                      format(turn % 2 + 1, turn))
                                if not TestMode:
                                    pygame.display.update()
                                    end_screen(turn % 2 + 1, turn)
                                    pygame.time.wait(
                                        2000
                                    )  # wait for a bit to allow the player to  B A S K  in their glory                       quit()
                                    return  # exit the game loop and quit
                                return
                        else:
                            log.info("Unable to place piece on column " +
                                     str(col))
                            turn -= 1
                        renderer(playField)
                        pygame.display.update()
                        turn += 1

            if event.type == pygame.KEYDOWN:
                # Bit of code for Mark, because he asked for the game to export its current state
                if event.key == pygame.K_F6 and turn % 2 == 1:
                    # Check if the user pressed F6 then export
                    log.debug("Exporting current game state...")
                    flattenAndExport(playField)
                if event.key == pygame.K_t:
                    TestMode = not TestMode
                    renderer(playField)
                    pygame.display.flip()
                    log.debug("Test Mode set to {}".format(TestMode))
                    start_game()
                if event.key == pygame.K_d:
                    DataGatherMode = not DataGatherMode
                    log.debug(
                        "Data Gather mode set to {}".format(DataGatherMode))
                if event.key == pygame.K_a:
                    AIMode = not AIMode
                    if AIMode and (not AI):
                        try:
                            # AI = keras.models.load_model('AI.model')    # If first time AI toggles, imports the NN
                            nn._construct("AI")
                            # nn._save_model("AI")
                            AI = True
                            log.info("Neural Network model loaded")
                        except:
                            log.error("Failed to load Neural Network model")
                            AIMode = False  # Ensures not trying to get info from absent AI
                    log.debug("AI mode set to {}".format(AIMode))

        if TestMode:
            col = _input(playField, turn, 1)
            if col is not None:  # None = the user didnt click in a valid location, so we ignore it
                row = _get_next_open_row(
                    playField,
                    col)  # determine what row we should place a piece
                if row != -1:
                    _drop_piece(playField, row, col,
                                turn % 2 + 1)  # drop said piece
                    if _winning_move(playField, turn % 2 +
                                     1):  # check if a player has won
                        log.info(
                            "Win condition met for player {}".format(turn % 2 +
                                                                     1))
                        renderer(playField)
                        hueHSV = hueHSV + 1
                        pygame.display.update()
                        print("Player {} is the Winner in {} turns!".format(
                            turn % 2 + 1, turn))
                        pygame.time.wait(10)

                        return
                    turn += 1
        unique, counts = np.unique(playField, return_counts=True)
        dictionary = dict(zip(unique, counts))
        try:
            if dictionary[0] == 0:
                return
        except KeyError:
            log.warning("Playfield full, restarting...")
            renderer(playField)
            pygame.display.update()
            return
        except ValueError:
            pass
예제 #10
0
from logManager import log
import os
# import keras
import random
import NeuralNetwork as nn

ROW_COUNT = 6
COLUMN_COUNT = 7

AIMode = True
DataGatherMode = False
GatherMove = False
TestMode = False
hueHSV = 0

log.debug("AI mode set to {}".format(AIMode))
log.debug("Data Gather mode set to {}".format(DataGatherMode))
log.debug("Test Mode set to {}".format(TestMode))
pygame.init()
width = (COLUMN_COUNT + 2) * 100
height = (ROW_COUNT + 1) * 100
size = (width, height)
radius = int(100 / 2 - 5)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Connect 4 AI Game")
logo_image = pygame.image.load("unnamed.png")
pygame.display.set_icon(logo_image)
turn = 0  # Variable to hold turn for UI
AI = False  # Variable for NN, set to 0 before loaded

# Text objects
예제 #11
0
def main_menu():
    """
    The main menu screen
    :return: None
    """
    # Escape condition if test mode is enabled
    if TestMode:
        return

    log.info("Loading main menu")
    main = True
    counter = 0
    difficulty = ["Easy", "Medium", "Hard"]
    # Variables to hold various colours
    blue = (29, 92, 193)
    white = (255, 255, 255)
    black = (0, 0, 0)
    yellow = (255, 255, 0)
    dark_yellow = (210, 225, 0)
    red = (255, 0, 0)
    dark_red = (210, 0, 0)
    # Renders text for each button
    text_surface = small_text.render(difficulty[counter], True, black)
    text_surface1 = large_text.render("Connect 4", True, black)
    text_surface2 = small_text.render("Play", True, black)
    text_surface3 = small_text.render("Quit", True, black)

    screen.fill(blue)
    # Draws the main title
    text_rect = text_surface1.get_rect()
    text_rect.center = ((width / 2), (height / 2))
    screen.blit(text_surface1, text_rect)

    #Loop to update the main menu while it is in use
    while main:
        for event in pygame.event.get():
            if event.type != pygame.MOUSEMOTION:
                log.debug(event)
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        # Variables to store mouse information
        mouse = pygame.mouse.get_pos()
        click = pygame.mouse.get_pressed()
        # If statement to respond to users interaction with play button
        if 225 + 150 > mouse[0] > 225 and 550 + 50 > mouse[1] > 550:
            # Change button colour while it is under cursor
            pygame.draw.rect(screen, dark_yellow, (225, 550, 150, 50))
            # End loop and take player to the game if they click play
            if click[0] == 1:
                screen.fill(black)
                main = False
        else:
            pygame.draw.rect(screen, yellow, (225, 550, 150, 50))

        # If statement to respond to users interaction with quit button
        if 525 + 150 > mouse[0] > 525 and 550 + 50 > mouse[1] > 550:
            # Change button colour while it is under cursor
            pygame.draw.rect(screen, dark_red, (525, 550, 150, 50))
            # Exit the game if the user presses quit
            if click[0] == 1:
                pygame.quit()
                quit()

        else:
            pygame.draw.rect(screen, red, (525, 550, 150, 50))

        # If statement to respond to users interaction with difficulty button
        if 375 + 150 > mouse[0] > 375 and 450 + 50 > mouse[1] > 450:
            # Change button colour while it is under cursor
            pygame.draw.rect(screen, dark_yellow, (375, 450, 150, 50))
            # Changes counter that corresponds with difficulty type if clicked
            if click[0] == 1:

                if counter == 2:
                    counter = 0
                else:
                    counter += 1
                # Renders text with new difficulty setting
                text_surface = small_text.render(difficulty[counter], True,
                                                 black)
                pygame.time.wait(100)
        else:
            pygame.draw.rect(screen, yellow, (375, 450, 150, 50))

        # Draws difficulty text onto button
        text_rect = text_surface.get_rect()
        text_rect.center = ((375 + (150 / 2)), (450 + (50 / 2)))
        screen.blit(text_surface, text_rect)

        # Draws play text onto button
        text_rect = text_surface2.get_rect()
        text_rect.center = ((225 + (150 / 2)), (550 + (50 / 2)))
        screen.blit(text_surface2, text_rect)

        # Draws quit text onto button
        text_rect = text_surface3.get_rect()
        text_rect.center = ((525 + (150 / 2)), (550 + (50 / 2)))
        screen.blit(text_surface3, text_rect)

        # Updates display
        pygame.display.update()
예제 #12
0
import logging
from logManager import log

log.info('Program Begin\n')


log.info('Importing Packages')
import tensorflow as tf
log.debug('\tImported TensorFlow')			#TensorFlow 1.5
import keras
log.debug('\tImported Keras')
import numpy as np
log.debug('\tImported Numpy')
#import matplotlib.pyplot as plt			#Just to see end result, not required for purpose
#print('\tImported Matplotlib.Pyplot')
log.info('\tImporting Done\n')


log.debug('Setting Initial Variables')
bannerChar = '¬'
log.debug('\tVariables Set\n')



log.debug('Creating Dataset')
mnist = keras.datasets.mnist			#In practice, would probably be replaced with X000 possible game states
log.debug('\tDataset Created\n')


log.debug('Loading Data')
(xTrain, yTrain), (xTest, yTest) = mnist.load_data()