<jupyter_start><jupyter_text>Mine-Sweeper and Neural Networks Getting Started The goals of this project were to gain experience in trying to translate a problem into one solvable with neural networks. Beating a game of Mine-Sweeper, through predicting mine spaces, is not something that can be solved with iterative functions, so neural nets must be used. Even using neural nets, the problem can not be “solved” as it is NP-Complete, but with the proper training a net can get to the point where it can reliably do fairly well.The data from Dataproduction.ipynb will be stored in "test.csv" and "train.csv". We will also need to import sympy, numpy, and keras. We will load the files into X and Y.<jupyter_code>import sympy as sp
import numpy as np
import keras
#            '/path/to/train.csv'
X=np.loadtxt('/home/djc6w/S20-team4-project/Project Stuff/train.csv', delimiter = ',')
X=X.astype('float32')
#            'path/to/test.csv'
Y=np.loadtxt('/home/djc6w/S20-team4-project/Project Stuff/test.csv', delimiter = ',')
Y=Y.astype('float32')<jupyter_output>Using TensorFlow backend.<jupyter_text>Now we need to reshape the data to make it trainable.<jupyter_code>x_train = np.zeros((X.shape[0],9,9,1))
for i in range(X.shape[0]):
    x_train[i,:,:,0] = X[i].reshape(9,9)
y_train = Y<jupyter_output><empty_output><jupyter_text>The DataLet's see what our training data looks like!<jupyter_code>temp = x_train[2,:,:,0].round(decimals=1)
display(sp.Matrix(temp))
display(sp.Matrix(y_train[2].reshape(9,9)))<jupyter_output><empty_output><jupyter_text>Beautiful, 9x9 grids full of a few known values based on essentially a couple of random moves in the game. The ModelNow let's develop our model.<jupyter_code>model = keras.Sequential()
model.add(keras.layers.Conv2D(18, kernel_size=(6,6),
                              activation = 'relu',
                              data_format='channels_last',
                              input_shape=[x_train.shape[1],
                                          x_train.shape[2],
                                          x_train.shape[3]]))
model.add(keras.layers.Conv2D(3,(3,3),activation='relu'))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(162,activation='relu'))
model.add(keras.layers.Dense(81, activation='sigmoid'))

model.compile(loss=keras.losses.binary_crossentropy,
              optimizer=keras.optimizers.SGD(lr=0.01),
              metrics=['accuracy'])
model.summary()<jupyter_output>Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 4, 4, 18)          666       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 2, 2, 3)           489       
_________________________________________________________________
flatten_1 (Flatten)          (None, 12)                0         
_________________________________________________________________
dense_1 (Dense)              (None, 162)               2106      
_________________________________________________________________
dense_2 (Dense)              (None, 81)                13203     
=================================================================
Total params: 16,464
Trainable params: 16,464
Non-trainable params: 0
__________________________________________________[...]<jupyter_text>For our demo, we have our weights for a previously trained model available to load. However, this is only necessary if you want to see strictly the results.<jupyter_code>#Uncomment and run this to load weights from the previously trained model
#Make sure to adjust the path to where you have it stored
#model.load_weights('/home/djc6w/S20-team4-project/Project Stuff/model.h5')<jupyter_output><empty_output><jupyter_text>The code below is used to display a plot model of our convolutional network.<jupyter_code>from keras.utils.vis_utils import plot_model
# Visualization
plot_model(model,to_file='encdec.png',show_shapes=True,expand_nested=True)<jupyter_output><empty_output><jupyter_text>TrainingNow let's train! It is recommended that you train this net with a small batch size (1-10) and in smaller numbers of epochs over an extended period of time in order to avoid errors due to rapid, unexpected, val-loss. Be patient though! It may take a good number of training sessions to see satisfying results.<jupyter_code>batch_size = 4
epochs = 300
history = model.fit(x_train,y_train,
                   batch_size=batch_size,
                   epochs=epochs,
                   verbose=1)<jupyter_output><empty_output><jupyter_text>This will display the accuracy and val-loss diagrams for the model at its currently trained state.<jupyter_code>import matplotlib.pyplot as plt
plt.figure(1)
plt.subplot(211)

plt.plot(history.history['accuracy'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train','val'],loc='upper left')

plt.subplot(212)
plt.plot(history.history['loss'])
plt.title('model loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train','val'], loc='upper left')

plt.tight_layout()
plt.show()
score = model.evaluate(x_train, Y, verbose=1)
print('Test loss: ', score[0])
print('Test accuracy: ', score[1])<jupyter_output>5339/5339 [==============================] - 0s 53us/step
Test loss:  0.2663592856895792
Test accuracy:  0.46650430560112<jupyter_text>ResultsBelow, use this to display what the net is actually doing in comparison to the reality of the board state.The first matrix shown is the incomplete boardstate that was fed into the net. Keep in mind that in the training matrix, the 1s are representative of completely unrevealed spaces, while in the predictions and the final board, the 1s are representative of known mines.These matrices are made up of probabilities, so when the net predicts say a 0.8 then it is stating that it believes there is an 80% chance that a mine is in that space.The second matrix shown is the predictions made by the net, aiming to guess the completed board state.The third matrix shown is the completed board state.<jupyter_code>preds = model.predict(x_train[:,:,:,:]).astype("float32")
preds = preds.round(decimals=1)
temp = x_train[42,:,:,0].round(decimals=1)
print("Play Area")
display(sp.Matrix(temp))
print("Predicted Values")
display(sp.Matrix(preds[42].reshape(9,9)))
print("Actual Values")
display(sp.Matrix(y_train[42].reshape(9,9)))<jupyter_output>Play Area<jupyter_text>The GameThis is where the game implementation begins. These functions are used to predict a move to make through the net and convert it into an acceptable input for the game.<jupyter_code>def min_net(pred, env):
    retx = -1
    rety = -1
    temp = 1.0
    for lorge in range(9):
        for x in range(9):
            for y in range(9):
                if(float(env[x,y])==float(1.0)):
                    if(float(pred[x,y]) < float(lorge*0.1)):
                        if(float(pred[x,y])<temp):
                            retx = x
                            rety = y
                            temp = pred[x,y]
                    
        if(retx > -1):
            return(retx,rety)
        
    return(x,y)
    #print(pred.shape)
    
    
                    
def coordinate_net(y,x):
    #print(x)
    #print(y)
    a = chr(x+97)
    #print(a)
    b = chr(y+49)
    #print(a+b)
    return (a+b)
                
    


#this,that = min_net(sp.Matrix(preds[2].reshape(9,9)), sp.Matrix(x_train[2,:,:,0]))
#print(this,that)
#coordinate_net(this,that)<jupyter_output><empty_output><jupyter_text>This is the code for the actual game. It generates a simple implementation of Minesweeper, represented through text.At the end of this code block, the playgame() function is called, beginning the net's attempt at playing through the given boardstate.<jupyter_code>import numpy as np
import random
import csv
import re
import time
import random
from string import ascii_lowercase



def setupgrid(gridsize, start, numberofmines):
    # Initialize empty grid
    emptygrid = [['0' for i in range(gridsize)] for i in range(gridsize)]
    
    mines = getmines(emptygrid, start, numberofmines)
    
    # Label mine spaces
    for i, j in mines:
        emptygrid[i][j] = 'X'

    grid = getnumbers(emptygrid)

    return (grid, mines)

# Output the grid
def showgrid(grid):
    gridsize = len(grid)

    horizontal = '   ' + (4 * gridsize * '-') + '-'

    # Print top column letters
    toplabel = '     '

    for i in ascii_lowercase[:gridsize]:
        toplabel = toplabel + i + '   '

    print(toplabel + '\n' + horizontal)

    # Print left row numbers
    for idx, i in enumerate(grid):
        row = '{0:2} |'.format(idx + 1)

        for j in i:
            row = str(row) + ' ' + str(j) + ' |'

        print(row + '\n' + horizontal)

    print('')


def getrandomcell(grid):
    gridsize = len(grid)

    a = random.randint(0, gridsize - 1)
    b = random.randint(0, gridsize - 1)

    return (a, b)

# Used to initialize neighboring cells / safe cells
def getneighbors(grid, rowno, colno):
    gridsize = len(grid)
    neighbors = []

    for i in range(-1, 2):
        for j in range(-1, 2):
            if i == 0 and j == 0:
                continue
            elif -1 < (rowno + i) < gridsize and -1 < (colno + j) < gridsize:
                neighbors.append((rowno + i, colno + j))

    return neighbors

# Once the neighbors are initialized, this fills in random remaining spaces,
# excluding the starting cell and neighbors, up to the requested number of mines
def getmines(grid, start, numberofmines):
    mines = []
    neighbors = getneighbors(grid, *start) # initialize unavailable spaces

    for i in range(numberofmines):
        cell = getrandomcell(grid)
        while cell == start or cell in mines or cell in neighbors:
            cell = getrandomcell(grid)
        mines.append(cell)

    return mines


def getnumbers(grid):
    for rowno, row in enumerate(grid):
        for colno, cell in enumerate(row):
            if cell != 'X':
                # Gets the values of the neighbors
                values = [grid[r][c] for r, c in getneighbors(grid,
                                                              rowno, colno)]

                # Counts how many are mines
                grid[rowno][colno] = str(values.count('X'))

    return grid


def showcells(grid, currgrid, rowno, colno):
    # Exit function if the cell was already shown
    if currgrid[rowno][colno] != ' ':
        return

    # Show current cell
    currgrid[rowno][colno] = grid[rowno][colno]

    # Get the neighbors if the cell is empty
    if grid[rowno][colno] == '0':
        for r, c in getneighbors(grid, rowno, colno):
            # Repeat function for each neighbor that doesn't have a flag
            if currgrid[r][c] != 'F':
                showcells(grid, currgrid, r, c)


def playagain():
    choice = input('Play again? (y/n): ')

    return choice.lower() == 'y'


def parseinput(inputstring, gridsize, helpmessage):
    cell = ()
    flag = False
    message = "Invalid cell. " + helpmessage

    # Reformat input for more flexible acceptance
    pattern = r'([a-{}])([0-9]+)(f?)'.format(ascii_lowercase[gridsize - 1])
    validinput = re.match(pattern, inputstring)

    # Enter input into the associated grid space
    if inputstring == 'help':
        message = helpmessage

    elif validinput:
        rowno = int(validinput.group(2)) - 1
        colno = ascii_lowercase.index(validinput.group(1))
        flag = bool(validinput.group(3))

        if -1 < rowno < gridsize:
            cell = (rowno, colno)
            message = ''

    return {'cell': cell, 'flag': flag, 'message': message}

def getmove(grid, currgrid):
    if not grid:
        rand = random.randrange(10)
        rand2 = str(chr(random.randrange(0,9)+97))
        ret = rand2 + str(rand)
        return ret
    for x in range(0,9):
        for y in range(0,9):
            if (currgrid[x][y] == ' ' and grid[x][y] != 'X'):
                ret = str(chr(y+97)) + str(x+1)
                return ret
        
def pushtest(grid):
    newgrid = np.array(csvprep(grid))
    with open ('test.csv', mode='a') as grid_file:
        file_writer = csv.writer(grid_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        file_writer.writerow(newgrid.flatten())
    grid_file.close()

def pushtrain(grid):
    newgrid = np.array(csvprep(grid))
    with open ('train.csv', mode='a') as grid_file:
        file_writer = csv.writer(grid_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        file_writer.writerow(newgrid.flatten())
    grid_file.close()

    
##############################
#Change encoding values here
##############################
    
    
def csvprep(grid):
    newgrid = [row[:]for row in grid]
    for x in range(0,9):
        for y in range(0,9):
            if grid[x][y] == ' ':
                newgrid[x][y] = 1
            if grid[x][y] == '0':
                newgrid[x][y] = 0.0
            if grid[x][y] == '1':
                newgrid[x][y] = 0.1
            if grid[x][y] == '2':
                newgrid[x][y] = 0.2
            if grid[x][y] == '3':
                newgrid[x][y] = 0.3
            if grid[x][y] == '4':
                newgrid[x][y] = 0.4
            if grid[x][y] == '5':
                newgrid[x][y] = 0.5
            if grid[x][y] == '6':
                newgrid[x][y] = 0.6
            if grid[x][y] == '7':
                newgrid[x][y] = 0.7
            if grid[x][y] == '8':
                newgrid[x][y] = 0.8
            if grid[x][y] == 'X':
                newgrid[x][y] = 1
    return newgrid
     
def promptread():
    fstream=open('response.txt','r')
    thing = fstream.read()
    fstream.close()
    return thing

#
def feedbackload(flagcheck):
    fstream=open('response.txt','w')
    fstream.write(flagcheck)
    fstream.close()

def playgame():
    count = 0
    gridsize = 9
    numberofmines = 10
    flagcheck = True

    currgrid = [[' ' for i in range(gridsize)] for i in range(gridsize)]

    grid = []
    flags = []
    starttime = 0

    helpmessage = ("Type the column followed by the row (eg. a5). "
                   "To put or remove a flag, add 'f' to the cell (eg. a5f).")

    #showgrid(currgrid)
    print(helpmessage + " Type 'help' to show this message again.\n")
    while True:
        minesleft = numberofmines - len(flags)
        newgrid = np.array(csvprep(currgrid))
        i = np.zeros((1,9,9,1))
        i[0,:,:,0] = newgrid
        x,y = min_net(model.predict(i).reshape(9,9),newgrid)
        prompt = coordinate_net(x,y)
        print(prompt)
        #print(prompt)
        if not prompt:
            playgame()
        #prompt = input('Enter the cell ({} mines left): '.format(minesleft))
        #prompt=promptread()
        result = parseinput(prompt, gridsize, helpmessage + '\n')

        message = result['message']
        cell = result['cell']

        if cell:
            #print('\n\n')
            rowno, colno = cell
            currcell = currgrid[rowno][colno]
            flag = result['flag']

            if not grid:
                grid, mines = setupgrid(gridsize, cell, numberofmines)
            if not starttime:
                starttime = time.time()

            if flag:
                # Add a flag if the cell is empty
                if currcell == ' ':
                    currgrid[rowno][colno] = 'F'
                    flags.append(cell)
                # Remove the flag if there is one
                elif currcell == 'F':
                    currgrid[rowno][colno] = ' '
                    flags.remove(cell)
                else:
                    message = 'Cannot put a flag there'

            # If there is a flag there, show a message
            elif cell in flags:
                message = 'There is a flag there'

            elif grid[rowno][colno] == 'X':
                print('Game Over\n')
                showgrid(grid)
                flagcheck=False
                if playagain():
                    playgame()
                return

            elif currcell == ' ':
                showcells(grid, currgrid, rowno, colno)

            else:
                message = "That cell is already shown"
                
            
            #if set(flags) == set(mines):
            #    minutes, seconds = divmod(int(time.time() - starttime), 60)
            #    print(
            #        'You Win. '
            #        'It took you {} minutes and {} seconds.\n'.format(minutes,
            #                                                          seconds))
            #    showgrid(grid)
            #    if playagain():
            #        playgame()
            #    return
        showgrid(currgrid)       
        
        print(message)
        

playgame()<jupyter_output>Type the column followed by the row (eg. a5). To put or remove a flag, add 'f' to the cell (eg. a5f). Type 'help' to show this message again.

i1
     a   b   c   d   e   f   g   h   i   
   -------------------------------------
 1 |   |   |   |   | 1 | 0 | 0 | 0 | 0 |
   -------------------------------------
 2 |   |   |   |   | 1 | 0 | 0 | 0 | 0 |
   -------------------------------------
 3 |   |   |   |   | 1 | 1 | 1 | 1 | 0 |
   -------------------------------------
 4 |   |   |   |   |   |   |   | 2 | 0 |
   -------------------------------------
 5 |   |   |   |   |   |   |   | 2 | 0 |
   -------------------------------------
 6 |   |   |   |   |   |   |   | 2 | 1 |
   -------------------------------------
 7 |   |   |   |   |   |   |   |   |   |
   -------------------------------------
 8 |   |   |   |   |   |   |   |   |   |
   -------------------------------------
 9 |   |   |   |   |   |   |   |   |   |
   -------------------------------------


h9
     a   b   c   d   e   f  [...]
{'fraction_non_alphanumeric': 0.14650994373572504, 'fraction_numerical': 0.018494791376524985, 'mean_word_length': 2.1351728955640934, 'pattern_counts': {'":': 0, '<': 48, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '613482', 'license': 'MIT', 'n_tokens_mistral': 5710, 'n_tokens_neox': 5381, 'n_words': 1531, 'path': 'Project Stuff/DemoNotebook.ipynb', 'repo_name': 'CSCI4850/S20-team4-project', 'size': '17951'}