commit 9825def2536f50708ca3e21d126a832dbef72095 Author: Simeon Keske Date: Wed Aug 7 21:49:40 2019 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee1675f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.fiar +__pycache__ diff --git a/PvN.py b/PvN.py new file mode 100644 index 0000000..3e82e33 --- /dev/null +++ b/PvN.py @@ -0,0 +1,43 @@ +import fiar +import nn +import lib + +game = fiar.FIAR(); +nn = lib.loadSingle(0) + +def declareWinner(): + game.printField(); + print("And the winner is P", game.proveWinner(), "!") + +def isnumber(val): + try: + val = int(val) + return True + except ValueError: + return False + + +while True: + game.printField(); + + player_input = input("P1, where do you put your stone? ") + + while not (isnumber(player_input) and 7 >= int(player_input) >= 1): + player_input = input("P1, your input has to be a number between 1 and 7! New input: ") + + try: + game.setStone(int(player_input)-1, 1) + except OverflowError: + print("This Column is already full, maybe try again next time...") + + if(game.proveWinner()): + declareWinner() + break + + # --------------- # + + game = lib.nextNNmove(nn, game, 2); + + if(game.proveWinner()): + declareWinner() + break diff --git a/PvP.py b/PvP.py new file mode 100644 index 0000000..4420bc4 --- /dev/null +++ b/PvP.py @@ -0,0 +1,51 @@ +import fiar + +game = fiar.FIAR(); + +def declareWinner(): + game.printField(); + print("And the winner is P", game.proveWinner(), "!") + + +def isnumber(val): + try: + val = int(val) + return True + except ValueError: + return False + + +while True: + game.printField(); + + player_input = input("P1, where do you put your stone? ") + + while not (isnumber(player_input) and 7 >= int(player_input) >= 1): + player_input = input("P1, your input has to be a number between 1 and 7! New input: ") + + try: + game.setStone(int(player_input)-1, 1); + except OverflowError: + print("This Column is already full, maybe try again next time...") + + if(game.proveWinner()): + declareWinner() + break + + # --------------- # + + game.printField(); + + player_input = input("P2, where do you put your stone? ") + + while not (isnumber(player_input) and 7 >= int(player_input) >= 1): + player_input = input("P2, your input has to be a number between 1 and 7! New input: ") + + try: + game.setStone(int(player_input)-1, 2); + except OverflowError: + print("This Column is already full, maybe try again next time...") + + if(game.proveWinner()): + declareWinner() + break diff --git a/fiar.py b/fiar.py new file mode 100644 index 0000000..2d72d8c --- /dev/null +++ b/fiar.py @@ -0,0 +1,121 @@ +class FIAR(): + def __init__(self, height=6, width=7): + self.height = height # y + self.width = width # x + self.field = [] + # field[x][y] + for x in range(width): + col = [] + for y in range(height): + col.append(None) + self.field.append(col) + + def getTransformedField(self): + output = [] + for col in self.field: + output += col + return output + + def printField(self): + redBG = "\33[41m" + greenBG = "\33[42m" + clearBG = "\33[0m" + dashes = (self.width * 2)+1 + print("-" * dashes) + for y in range(self.height, -1, -1): + for x in range(self.width): + if y == self.height: + print("|" + str(x+1), end='') + elif self.field[x][y] == 1: + print("|" + redBG + "x" + clearBG, end='') + elif self.field[x][y] == 2: + print("|" + greenBG+"o" + clearBG, end='') + else: + print("|" + " ", end='') + print("|") + print("-" * dashes) + + def setStone(self, col, player): + if(col in list(range(self.width))): + has_set = False + for i in range(self.height): + if self.field[col][i] == None: + self.field[col][i] = player + has_set = True + break + if not has_set: + raise OverflowError + else: + raise IndexError + + def proveWinner(self): + # Tie: + tie = True + for x in range(self.width): + if(self.field[x][self.height-1] == None): + tie = False + break + if tie: + return 3 + + # Horizontal: + for y in range(self.height): + for x in range(self.width-3): + if self.field[x][y] != None: + first = self.field[x][y] + isWinner = True + + for i in range(1, 4): + if self.field[x+i][y] != first: + isWinner = False + break + + if isWinner: + return first + + # Vertical: + for x in range(self.width): + for y in range(self.height-3): + if self.field[x][y] != None: + first = self.field[x][y] + isWinner = True + + for i in range(1, 4): + if self.field[x][y+i] != first: + isWinner = False + break + + if isWinner: + return first + + # Diagonal Up: + for x in range(self.width-3): + for y in range(self.height-3): + if self.field[x][y] != None: + first = self.field[x][y] + isWinner = True + + for i in range(1, 4): + if self.field[x+i][y+i] != first: + isWinner = False + break + + if isWinner: + return first + + # Diagonal Down: + for x in range(3, self.width): + for y in range(self.height-3): + if self.field[x][y] != None: + first = self.field[x][y] + isWinner = True + + for i in range(1, 4): + if self.field[x-i][y+i] != first: + isWinner = False + break + + if isWinner: + return first + + return False diff --git a/lib.py b/lib.py new file mode 100644 index 0000000..411c976 --- /dev/null +++ b/lib.py @@ -0,0 +1,58 @@ +import nn +import pickle + +networks_filename = "networks.fiar" + +def nextNNmove(network, game, player): + flatfield = game.getTransformedField() + player1 = [] + player2 = [] + for spot in flatfield: + if spot == 1: + player1.append(1) + player2.append(0) + elif spot == 2: + player1.append(0) + player2.append(1) + else: + player1.append(0) + player2.append(0) + + out = network.calculateOutput(player1+player2) + preferences = [] + for i in range(len(out)): + maxI = 0 + maxVal = -20 + for j in range(len(out)): + if out[j] > maxVal: + maxVal = out[j] + maxI = j + out[maxI] = -20 + preferences.append(maxI) + + for val in preferences: + try: + game.setStone(val, player) + except OverflowError: + pass + else: + break + return game + +def createAndSave(num): + nets = [] + for i in range(num): + nets.append(nn.NN(84, 168, 168, 84, 84, 42, 7)) + saveAll(nets) + +def saveAll(nets): + with open(networks_filename, 'wb') as networks_file: + pickle.dump(nets, networks_file) + +def loadAll(): + with open(networks_filename, 'rb') as networks_file: + nets = pickle.load(networks_file) + return nets + +def loadSingle(num): + return loadAll()[num] diff --git a/nn.py b/nn.py new file mode 100644 index 0000000..91e5705 --- /dev/null +++ b/nn.py @@ -0,0 +1,40 @@ +import numpy as np + +class NN(): + score = 0 + + def __init__(self, *args): + self.layers = args + self.synapses = [] + for i in range(len(self.layers)-1): + self.synapses.append(np.random.normal(scale=1,size=(self.layers[i], self.layers[i+1]))) + + def calculateOutput(self, input): + layerInput = input + + for synapseLayer in self.synapses: + layerInput = np.dot(layerInput, synapseLayer) + layerInput = self.sigmoid(layerInput) + + return layerInput + + def sigmoid(self, s): + #print("Arr:", arr) + #s = np.array(arr) + # activation function + res = 1 / (1 + np.exp(-s)) + #print("Res:", res) + return res + + def getSynapses(self): + return self.synapses + + def setSynapses(self, synapses): + self.synapses = synapses + + def mutate(self, val): + mut_arr = [] + for i in range(len(self.layers)-1): + mut_arr.append(np.random.normal(scale=val,size=(self.layers[i], self.layers[i+1]))) + self.synapses = np.add(self.synapses, mut_arr) + return mut_arr diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..44f27a2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +numpy +pickle diff --git a/training.py b/training.py new file mode 100644 index 0000000..c91107c --- /dev/null +++ b/training.py @@ -0,0 +1,63 @@ +import lib, fiar + +nets = lib.loadAll() +gen = 0 + +def NvN(net1, net2, printField=False): + game = fiar.FIAR(); + + while True: + game = lib.nextNNmove(net1, game, 1); + if(game.proveWinner()): + break + game = lib.nextNNmove(net2, game, 2); + if(game.proveWinner()): + break + + if printField: + game.printField() + print(net1.synapses[0][0][0]) + print() + + return game.proveWinner() + +try: + while True: + gen += 1 + print("Gen:", gen) + + # Reset the nets' score: + for net in nets: + net.score = 0 + + # Let the nets play against each other: + for i in range(len(nets)): + for j in range(i+1, len(nets)): + + + winner = NvN(nets[i], nets[j], i==0 and j==1) + #print("Net1:",i,"Net2:",j) + #print("Winner:",winner) + if(winner == 1): + nets[i].score += 1 + if(winner == 2): + nets[j].score += 1 + + winner = NvN(nets[j], nets[i]) + #print("Net1:",i,"Net2:",j) + #print("Winner:",winner) + if(winner == 1): + nets[i].score += 1 + if(winner == 2): + nets[j].score += 1 + + # Sort the nets by their score: + nets.sort(key=lambda x: x.score, reverse=True) + for i in range(int(len(nets)/3)): + nets[i+int(len(nets)/3)] = nets[i]; + nets[i+int(len(nets)/3)].mutate(0.001); + nets[i+int(len(nets)/3*2)] = nets[i]; + nets[i+int(len(nets)/3*2)].mutate(0.1); +except KeyboardInterrupt: + print("Saving all Data...") + lib.saveAll(nets)