This time, I made Conway's Game of Life instead of numerical simulation.
I started with the intention of taking a break, but when I made it, I was addicted to it, so I made a lot of trial and error. Therefore, the finished product is finally in a moving shape. If I understood the specifications, I think I could make something better, but I didn't feel like reading that much. .. ..
First, briefly explain about Conway's Game of Life. A life game is a type of cellular automaton that has information that the grid points are "alive" and "dead", and when the time (generation) advances by one, it is inside according to the given rules according to the surrounding situation. It changes the state of. As a typical rule, on a square grid, with respect to points around 8 squares, if 2 or 3 live, it will survive, and if there are 3 surviving grid points around it, it will be newly born. I think there are 3 etc. Since Conway's Game of Life is Turing complete, you can reproduce the computer inside Conway's Game of Life. For more information
<a href="http://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3% 83% A0 "target =" _ blank "title =" Life Game --Wikipedia: "> Life Game --Wikipedia: Life Game World 1 [ Complex system] --Nico Nico Douga: GINZA:
Please refer to. The video is especially recommended.
I wanted to make a life game using Tkinter, but it seemed to be difficult, so I made the rules of the life game first so that I could check it on the terminal.
That is next.
lifegame_console.py
#! /usr/bin/env python
# -*- coding:utf-8 -*-
#
# written by ssh0, June 2014.
import numpy as np
import sys
import time
import os
class LifeGame:
def __init__(self, L=50, rule="2 3/3"):
self.L = L # lattice size
p = 0.2
self.survive = [int(i) for i in rule.split("/")[0].split()]
self.birth = [int(i) for i in rule.split("/")[1].split()]
lattice = np.random.random([self.L+2, self.L+2])
self.lattice = lattice<p
self.lattice[0,:] = self.lattice[self.L+1,:] = False
self.lattice[:,0] = self.lattice[:,self.L+1] = False
def canvas_update(self):
os.system("clear")
print "\n"
l = ""
for y in range(1,self.L+1):
for x in range(1,self.L+1):
if self.lattice[x,y]:
l += u" ■"
else:
l += u" □"
l += "\n"
print l
print "\n"
time.sleep(0.1)
def progress(self):
L = self.L
Tmax = 2000
t = 0
while t < Tmax:
try:
self.canvas_update()
nextsites = []
#Periodic boundary conditions
self.lattice[0,0] = self.lattice[self.L,self.L]
self.lattice[0,self.L+1] = self.lattice[self.L,1]
self.lattice[self.L+1,0] = self.lattice[1,self.L]
self.lattice[self.L+1,self.L+1] = self.lattice[1,1]
for m in range(1, self.L+1):
self.lattice[m, self.L+1] = self.lattice[m, 1]
self.lattice[m, 0] = self.lattice[m, self.L]
self.lattice[0, m] = self.lattice[self.L, m]
self.lattice[self.L+1, m] = self.lattice[1, m]
#Judgment of adjacent grid points
for m in range(1,self.L+1):
for n in range(1,self.L+1):
if self.lattice[m,n]:
neighber = np.sum(self.lattice[m-1:m+2, n-1:n+2])-1
if neighber in self.survive:
nextsites.append((m,n))
else:
neighber = np.sum(self.lattice[m-1:m+2, n-1:n+2])
if neighber in self.birth:
nextsites.append((m,n))
#Update lattice
self.lattice[:] = False
for nextsite in nextsites:
self.lattice[nextsite] = True
t += 1
except KeyboardInterrupt:
print "stopped."
break
if __name__ == '__main__':
lg = LifeGame()
lg.progress()
The initial condition was that the points below the threshold in the matrix to which random numbers were assigned survived. For the display, I managed to clear the terminal first, and print the surviving sites as ■ and the other sites as □. If I set the delay time to less than 0.1, the flicker became worse in my environment, so I can't seem to make it any faster.
I'm making a video so please
<img src = "https://i.ytimg.com/vi/7KMluy0fRq8/2.jpg " alt = "Easy with Python" I made a Life Game (numpy) "border =" 0 "width =" 145 "height =" 109 "/> I made a simple Life Game with Python (numpy)
Next, I will introduce what I made using Tkinter's Canvas. The most difficult thing to make this was to be able to change the "life" and "death" of each grid by clicking. It may be easier to do this with Pygame, and as far as I've investigated, I've only seen people using it. However, I think the basics are the same, so I decided to use Tkinter itself, which I will continue to use. All are listed below.
lifegame.py
#! /usr/bin/env python
# -*- coding:utf-8 -*-
#
# written by ssh0, September 2014.
from tkinter import *
import numpy as np
import sys
# import time
class LifeGame:
def __init__(self, L=30, rule="2 3/3", p=None, pattern=None):
self.L = L # lattice size
self.survive = [int(i) for i in rule.split("/")[0].split()]
self.birth = [int(i) for i in rule.split("/")[1].split()]
if p:
lattice = np.random.random([self.L + 2, self.L + 2])
self.lattice = lattice < p
self.lattice[0, :] = self.lattice[self.L+1, :] = False
self.lattice[:, 0] = self.lattice[:, self.L + 1] = False
else:
self.lattice = np.zeros([self.L + 2, self.L + 2], dtype=bool)
if pattern:
for x, y in pattern:
self.lattice[x, y] = True
def progress(self, canvas_update, update):
Tmax = 2000
t = 0
self.loop = True
while self.loop:
try:
past_lattice = self.lattice.copy()
nextsites = []
#Periodic boundary conditions
self.lattice[0, 0] = self.lattice[self.L, self.L]
self.lattice[0, self.L + 1] = self.lattice[self.L, 1]
self.lattice[self.L + 1, 0] = self.lattice[1, self.L]
self.lattice[self.L + 1, self.L + 1] = self.lattice[1, 1]
for m in range(1, self.L+1):
self.lattice[m, self.L+1] = self.lattice[m, 1]
self.lattice[m, 0] = self.lattice[m, self.L]
self.lattice[0, m] = self.lattice[self.L, m]
self.lattice[self.L+1, m] = self.lattice[1, m]
#Judgment of adjacent grid points
for m in range(1, self.L + 1):
for n in range(1, self.L + 1):
if self.lattice[m, n]:
neighber = np.sum(self.lattice[m-1:m+2, n-1:n+2])-1
if neighber in self.survive:
nextsites.append((m, n))
else:
neighber = np.sum(self.lattice[m-1:m+2, n-1:n+2])
if neighber in self.birth:
nextsites.append((m, n))
#Update lattice
self.lattice[:] = False
for nextsite in nextsites:
self.lattice[nextsite] = True
#Drawing update
changed_rect = np.where(self.lattice != past_lattice)
for x, y in zip(changed_rect[0], changed_rect[1]):
if self.lattice[x, y]:
color = "green"
else:
color = "black"
canvas_update(x, y, color)
update()
# time.sleep(0.1)
t += 1
if t > Tmax:
self.loop = False
except KeyboardInterrupt:
print("stopped.")
break
class Draw_canvas:
def __init__(self, lg, L):
self.lg = lg
self.L = L
default_size = 640 # default size of canvas
self.r = int(default_size / (2 * self.L))
self.fig_size = 2 * self.r * self.L
self.margin = 10
self.sub = Toplevel()
self.sub.title("Life Game")
self.canvas = Canvas(self.sub, width=self.fig_size + 2 * self.margin,
height=self.fig_size + 2 * self.margin)
self.c = self.canvas.create_rectangle
self.update = self.canvas.update
self.rects = dict()
for y in range(1, self.L + 1):
for x in range(1, self.L + 1):
if self.lg.lattice[x, y]:
live = True
else:
live = False
tag = "%d %d" % (x, y)
self.rects[tag] = Rect(x, y, live, tag, self)
self.canvas.pack()
def canvas_update(self, x, y, color):
v = self.rects["%d %d" % (x, y)]
v.root.canvas.itemconfig(v.ID, fill=color)
class Rect:
def __init__(self, x, y, live, tag, root):
self.root = root
self.x = x
self.y = y
self.live = bool(live)
if live:
color = "green"
else:
color = "black"
self.ID = self.root.c(2*(x-1)*self.root.r + self.root.margin,
2*(y-1)*self.root.r + self.root.margin,
2*x*self.root.r + self.root.margin,
2*y*self.root.r + self.root.margin,
outline="#202020", fill=color, tag=tag)
self.root.canvas.tag_bind(self.ID, '<Button-1>', self.pressed)
def pressed(self, event):
if self.live:
self.live = False
color = "black"
else:
self.live = True
color = "green"
self.root.lg.lattice[self.x, self.y] = self.live
self.root.canvas.itemconfig(self.ID, fill=color)
class TopWindow:
def show_window(self, title="title", *args):
self.root = Tk()
self.root.title(title)
frames = []
for i, arg in enumerate(args):
frames.append(Frame(self.root, padx=5, pady=5))
for k, v in arg:
Button(frames[i], text=k, command=v).pack(expand=YES, fill='x')
frames[i].pack(fill='x')
self.root.mainloop()
class Main:
def __init__(self):
L = 100
rule = "2 3/3"
self.top = TopWindow()
c = L / 2
#Die hard
pattern = [(c-1, c+1), (c, c+1), (c, c+2), (c+4, c+2),
(c+5, c), (c+5, c+2), (c+6, c+2)]
self.lg = LifeGame(L, rule, p=None, pattern=pattern)
self.top.show_window("Life game", (('set', self.init),),
(('start', self.start),
('pause', self.pause)),
(('save', self.pr),),
(('quit', self.quit),))
def init(self):
self.DrawCanvas = Draw_canvas(self.lg, self.lg.L)
def start(self):
self.lg.progress(self.DrawCanvas.canvas_update, self.DrawCanvas.update)
def pause(self):
self.lg.loop = False
def pr(self):
import tkinter.filedialog
import os
if self.DrawCanvas is None:
return 1
fTyp = [('eps file', '*eps'), ('all files', '*')]
filename = tkinter.filedialog.asksaveasfilename(filetypes=fTyp,
initialdir=os.getcwd(),
initialfile='figure_1.eps')
if filename is None:
return 0
self.DrawCanvas.canvas.postscript(file=filename)
def quit(self):
self.pause()
sys.exit()
if __name__ == '__main__':
app = Main()
The difference from the previous lifegame_console.py is that the handling of small variables in LifeGame.init, canvas_update is set to another class Draw_canvas, and the part that draws the grid in it is divided into another class Rect. As a result, each grid point can be treated as an independent one, and if you press the grid point, you can switch between "life" and "death". I captured the actual execution, so please have a look (the latter half is just to follow the code connection, so if you are not interested, you can skip it).
<img src = "https://i.ytimg.com/vi/1M9sc5TlWQg/3.jpg " alt = "Life with Python" I made a game [Tkinter] "border =" 0 "width =" 145 "height =" 109 "/> I made a life game with Python [Tkinter]
This time I'm mostly playing, but I've learned new things and I think that the range of simulations in the future will expand. Also, subtitles and explanations should be added to the video. .. .. I would like to touch it a little more.
Recommended Posts