{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport time\nfrom scipy import ndimage\nfrom PIL import Image\nfrom matplotlib import pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Simple and fast game creation, keeping only the first gen and the last as we can see on train dataset.\n\n\n#### Rules for creation https://www.kaggle.com/c/conways-reverse-game-of-life-2020/data\n"},{"metadata":{},"cell_type":"markdown","source":"> * **Rules**\n\n1.  An initial board was chosen by filling the board with a random density between 1% full (mostly zeros) and 99% full (mostly ones).\n1.  This initial board was evolved 5 steps.\n1.  The starting board's state was recorded after the 5 \"warmup steps\". These are the values in the start variables.\n1.  The starting board was then evolved delta steps. Delta was chosen to be uniformly random between 1 and 5. If the stopping board was empty, the game was discarded.\n1.  The stopping board's state was then recorded. These are the values in the stop variables."},{"metadata":{},"cell_type":"markdown","source":"## Classes"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# Class responsible for generating n games.\n\nclass gameFactory:\n    def __init__(self,howmany):\n        self.howmany = howmany # how many games we want to have\n        value = howmany//5 #5 bins\n        self.distri = np.array([1]*value+[2]*value+[3]*value+[4]*value+[5]*value)\n        self.games = []\n        \n    def generate(self,size=25):\n        for k in self.distri:\n            actual_games = []\n            actual = gameCreator(size)\n            created = False\n            while not(created):\n                for i in range(k):\n                    actual.nextGen()\n                if actual.gens[-1].sum()>0: created=True\n                else: actual = gameCreator(size)\n            \n            actual_games = [actual.gens[0],actual.gens[-1]]\n            self.games.append(actual_games)\n    \n    # Converts created games into a dataframe\n    def to_df(self):\n        d = {'delta': self.distri}\n        df_delta = pd.DataFrame(data=d)\n        \n        df_columns = pd.read_csv(\"../input/conways-reverse-game-of-life-2020/train.csv\").drop([\"id\",\"delta\"],axis=1).columns\n                                 \n        ls_ = []\n        for k in self.games:\n            ls = np.concatenate((k[0].flatten() , k[1].flatten()), axis=0)\n            ls_.append(list(ls))\n     \n        df_data = pd.DataFrame(data=ls_, \n                                columns = df_columns)\n        \n        return pd.concat([df_delta, df_data], axis=1, sort=False)\n                ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Class responsible for creating a single game.\n\nclass gameCreator:\n    def __init__(self, grid):\n        self.size = grid\n        created = False\n        while not(created):\n            self.grid = np.random.randint(2, size=(grid,grid))\n            distribution = self.grid.sum()/(grid*grid)\n            if distribution > 0 or distribution < 1:\n                created = True\n        self.kernel = [[1,1,1],[1,0,1],[1,1,1]]\n        self.gens = [self.grid]\n        self.currentGen = 0\n        for k in range(5):\n            self.nextGen() # warmups\n            self.currentGen = 0\n            \n        self.gens = self.gens[5:]\n        #warmup setup ok\n    \n    def rules(self,number,alive):\n        if not(alive): \n            if number==3: return 1\n            else: return 0\n        if alive:\n            if number==1: return 0\n            if number==2: return 1\n            if number==3: return 1\n            if number>=4: return 0\n            else: return 0\n\n    \n    def filterApply(self,gen):\n        return (ndimage.convolve(np.pad(self.gens[gen],\n                                    [(1, ), (1, )], \n                                    mode='constant'),\n                                     self.kernel))[1:-1,1:-1]\n         \n    \n    def nextGen(self):\n        current = self.gens[self.currentGen].flatten()\n        filtered = self.filterApply(self.currentGen)\n        nextGen = []\n        for index,element in enumerate(filtered.flatten()):\n            nextGen.append(self.rules(element,current[index]))\n        self.currentGen+=1\n        self.gens.append(np.array(nextGen).reshape(self.size, self.size))\n        \n    def showAsImage(self,gen):\n        img = Image.fromarray(((1-self.gens[gen]) * 255).astype('uint8'), mode='L')\n        plt.figsize=(30, 30)\n        im = plt.imshow(img,cmap='hot')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Example creation of an 5x5 game."},{"metadata":{"trusted":true},"cell_type":"code","source":"game = gameCreator(5)\ngame.grid","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### We can get the next generation with obj.nextGen()"},{"metadata":{"trusted":true},"cell_type":"code","source":"game.nextGen()\ngame.gens","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Seeing as image"},{"metadata":{"trusted":true},"cell_type":"code","source":"game.showAsImage(1) #Pass the desired generation","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### With gameFactory we can creat alot of games fast, keeping only the first and last;"},{"metadata":{"trusted":true},"cell_type":"code","source":"b = gameFactory(100) #100 games\nb.generate() #size 25x25 default ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Here we use the to_df() method, to convert our data generated and create as pandas dataframe."},{"metadata":{"trusted":true},"cell_type":"code","source":"df = b.to_df()\ndf.delta.value_counts(normalize=True) #Here we can see that our delta is distributed","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.head(5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### And finally, lets create nth games.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"df = None\n\nnumberGames = 100 ##You may change here.\n\nini = time.time()\nb = gameFactory(numberGames)\nb.generate()\nend = time.time()\nprint(\"Time required to generate the games : {}\".format(end-ini))\nini = time.time()\ndf = b.to_df()\nend = time.time()\nprint(\"Time required to generate the dataframe : {}\".format(end-ini))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### And here we have nth samples created in df."},{"metadata":{"trusted":true},"cell_type":"code","source":"df.head(10)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"##     **Estimated time for creation:**\n\n*  100 samples : 8 seconds\n*  1000 samples : 20 seconds\n*  10000 samples : 140 seconds"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}