From 5e53c319645d79f2ad5b6c0e769d40480ceaaea6 Mon Sep 17 00:00:00 2001 From: Agnibho Mondal Date: Sat, 6 Dec 2014 16:08:46 +0530 Subject: [PATCH] Added toolbar and statusbar --- Board.py | 190 ++++++++++++++++++++++++++++++++++------------------ Cell.py | 18 ++++- README.TXT | 13 ++-- __main__.py | 4 +- 4 files changed, 148 insertions(+), 77 deletions(-) diff --git a/Board.py b/Board.py index efd61bd..1cd75f9 100644 --- a/Board.py +++ b/Board.py @@ -11,35 +11,53 @@ class Board(tk.Frame): DEPTH=50 start_dim=[] Num=0 - auto={} + Pop=-1 + Max=0 + mode="edit" timer={} + original={} def __init__(self, master=None): tk.Frame.__init__(self, master) self.grid() - self.auto=BooleanVar() self.stepnum=StringVar() + self.steppop=StringVar() def render(self, width, depth): self.WIDTH=width self.DEPTH=depth self.start_dim=[width, depth] + self.statusbar=tk.Frame(self) + self.steplbl=tk.Label(self.statusbar, textvariable=self.stepnum, padx=10) + self.poplbl=tk.Label(self.statusbar, textvariable=self.steppop, padx=10) self.contain=tk.Canvas(self, width=self.WIDTH*self.SIZE, height=self.DEPTH*self.SIZE) - self.contain.grid() + self.toolbar=tk.Frame(self) + self.startbtn=tk.Button(self.toolbar, text="Start", command=self.auto) + self.pausebtn=tk.Button(self.toolbar, text="Pause", state="disabled", command=self.pause) + self.stepbtn=tk.Button(self.toolbar, text="Next Step", command=self.step) + self.resetbtn=tk.Button(self.toolbar, text="Reset", command=self.reset) + self.revertbtn=tk.Button(self.toolbar, text="Revert", state="disabled", command=self.revert) + self.openbtn=tk.Button(self.toolbar, text="Open", command=self.openfile) + self.savebtn=tk.Button(self.toolbar, text="Save", command=self.savefile) + self.aboutbtn=tk.Button(self.toolbar, text="About", command=self.about) + self.statusbar.grid(row=0) + self.steplbl.grid(row=0, column=0) + self.poplbl.grid(row=0, column=1) + self.contain.grid(row=1) + self.toolbar.grid(row=2) + self.startbtn.grid(row=0, column=0) + self.pausebtn.grid(row=0, column=1) + self.stepbtn.grid(row=0, column=2) + self.resetbtn.grid(row=0, column=3) + self.openbtn.grid(row=1, column=0) + self.savebtn.grid(row=1, column=1) + self.revertbtn.grid(row=1, column=2) + self.aboutbtn.grid(row=1, column=3) + for i in range(0, self.WIDTH): self.cells.append([]) for j in range (0, self.DEPTH): self.cells[i].append(Cell.Cell(self.contain.create_rectangle(i*self.SIZE, j*self.SIZE, i*self.SIZE+self.SIZE, j*self.SIZE+self.SIZE, fill="white", outline="gray"), self.contain)) - self.startbtn=tk.Button(self, text="Start", command=self.start) - self.autobtn=tk.Checkbutton(self, text="Automatic", command=self.run, variable=self.auto) - self.stepbtn=tk.Button(self, text="Next Step", command=self.step) - self.resetbtn=tk.Button(self, text="Reset", command=self.reset) - self.openbtn=tk.Button(self, text="Open", command=self.openfile) - self.savebtn=tk.Button(self, text="Save", command=self.savefile) - self.steplbl=tk.Label(self, textvariable=self.stepnum) - self.steplbl.grid(row=1) - self.startbtn.grid(row=1, sticky="W") - self.openbtn.grid(row=1, sticky="E") def recreate(self, width, depth): self.contain.destroy() @@ -53,23 +71,75 @@ class Board(tk.Frame): else: self.SIZE=10 self.contain=tk.Canvas(self, width=self.WIDTH*self.SIZE, height=self.DEPTH*self.SIZE) - self.contain.grid(row=0) + self.contain.grid(row=1) for i in range(0, self.WIDTH): self.cells.append([]) for j in range (0, self.DEPTH): self.cells[i].append(Cell.Cell(self.contain.create_rectangle(i*self.SIZE, j*self.SIZE, i*self.SIZE+self.SIZE, j*self.SIZE+self.SIZE, fill="white", outline="gray"), self.contain)) - def start(self): + def run(self): for i in range(0, self.WIDTH): for j in range (0, self.DEPTH): self.cells[i][j].freeze() - self.startbtn.grid_remove() - self.openbtn.grid_remove() - self.stepbtn.grid(row=1, sticky="W") - self.resetbtn.grid(row=1, sticky="E") - self.autobtn.grid(row=2, sticky="W") - self.savebtn.grid(row=2, sticky="E") + self.original=self.cells + self.mode="man" + self.revertbtn["state"]="normal" + + def step(self): + if(self.Pop==0): + tkMessageBox.showwarning("Game over", "All life forms have been terminated") + return + if(self.mode=="edit"): + self.run() + for i in range(0, self.WIDTH): + for j in range (0, self.DEPTH): + z=self.count(i, j) + if(self.cells[i][j].getState()=="live"): + if(z<2 or z>3): + self.cells[i][j].makeDead() + elif(self.cells[i][j].getState()=="dead"): + if(z==3): + self.cells[i][j].makeLive() + self.Pop=0 + for i in range(0, self.WIDTH): + for j in range (0, self.DEPTH): + self.cells[i][j].commit() + if(self.cells[i][j].getState()=="live"): + self.Pop+=1 + if(self.Pop>self.Max): + self.Max=self.Pop + if(self.Pop>0): + self.Num+=1 + else: + tkMessageBox.showwarning("Game over", "All life forms have been terminated\nMaximun polpulation reached: "+str(self.Max)) + self.pause() + self.startbtn["state"]="disabled" + self.stepbtn["state"]="disabled" + if(self.WIDTH>30): + self.stepnum.set("Generation: "+str(self.Num)) + self.steppop.set("Population: "+str(self.Pop)) + else: + self.stepnum.set(str("Gen:"+str(self.Num))) + self.steppop.set("Pop:"+str(self.Pop)) + if(self.mode=="auto"): + self.timer=self.after(1000, self.step) + + def auto(self): + self.startbtn["state"]="disabled" + self.stepbtn["state"]="disabled" + self.pausebtn["state"]="normal" + if(self.mode=="edit"): + self.run() + self.mode="auto" + self.timer=self.after(1000, self.step) + + def pause(self): + self.startbtn["state"]="normal" + self.stepbtn["state"]="normal" + self.pausebtn["state"]="disabled" + self.mode="man" + self.after_cancel(self.timer) def openfile(self): filename=tkFileDialog.askopenfilename(filetypes=[("Life 1.06", "*.life"), ("Life 1.6", "*.lif"), ("All", "*")]) @@ -141,8 +211,7 @@ class Board(tk.Frame): while(arr[1][i]>self.DEPTH): arr[1][i]-=self.DEPTH for i in range(0, len(arr[0])): - self.cells[arr[0][i]][arr[1][i]].makeLive() - self.cells[arr[0][i]][arr[1][i]].commit() + self.cells[arr[0][i]][arr[1][i]].toggle() def writefile(self, filename): if(len(filename)>0): @@ -154,55 +223,42 @@ class Board(tk.Frame): f.write(str(i)+" "+str(j)+"\r\n") f.close() - def reset(self): - self.Num=0 - self.stepnum.set("") - if(self.WIDTH==self.start_dim[0] and self.DEPTH==self.start_dim[1]): - for i in range(0, self.WIDTH): - for j in range (0, self.DEPTH): - self.cells[i][j].makeDead() - self.cells[i][j].commit() - self.cells[i][j].unfreeze() - else: - self.recreate(self.start_dim[0], self.start_dim[1]) - self.stepbtn.grid_remove() - self.resetbtn.grid_remove() - self.autobtn.grid_remove() - self.savebtn.grid_remove() - self.startbtn.grid() - self.openbtn.grid() - if(self.auto.get()): - self.autobtn.invoke() - - def step(self): - self.Num+=1 - if(self.WIDTH>30): - self.stepnum.set("Generation: "+str(self.Num)) - else: - self.stepnum.set(str(self.Num)) + def reset(self, full=True): + self.Pop=0 for i in range(0, self.WIDTH): for j in range (0, self.DEPTH): - z=self.count(i, j) if(self.cells[i][j].getState()=="live"): - if(z<2 or z>3): - self.cells[i][j].makeDead() - elif(self.cells[i][j].getState()=="dead"): - if(z==3): - self.cells[i][j].makeLive() + self.Pop+=1 + if(self.Pop>0): + flag=tkMessageBox.askokcancel("Confirm Reset", "This action will erase all the cells from current board. Are you sure to continue?") + else: + flag=True + if(flag): + self.pause() + self.mode="edit" + self.Num=0 + self.Pop=-1 + self.Max=0 + self.stepnum.set("") + self.steppop.set("") + if(full): + if(self.WIDTH==self.start_dim[0] and self.DEPTH==self.start_dim[1]): + for i in range(0, self.WIDTH): + for j in range (0, self.DEPTH): + self.cells[i][j].clear() + else: + self.recreate(self.start_dim[0], self.start_dim[1]) + self.revertbtn["state"]="disabled" + + def revert(self): + self.reset(False) for i in range(0, self.WIDTH): for j in range (0, self.DEPTH): - self.cells[i][j].commit() - if(self.auto.get()): - self.timer=self.after(1000, self.step) - - def run(self): - if(self.auto.get()): - self.stepbtn["state"]="disabled" - self.timer=self.after(1000, self.step) - else: - self.stepbtn["state"]="normal" - self.after_cancel(self.timer) - + self.cells[i][j].revert() + + def about(self): + tkMessageBox.showinfo("About Life", "Life 1.03 by Agnibho Mondal\nBased on Conway's Game of Life\nhttp://code.agnibho.com/life") + def count(self, i, j): z=0 for cl in [self.getCell(i-1, j-1), self.getCell(i-1, j), self.getCell(i, j-1), self.getCell(i+1, j+1), self.getCell(i+1, j), self.getCell(i, j+1), self.getCell(i-1, j+1), self.getCell(i+1, j-1)]: diff --git a/Cell.py b/Cell.py index f7094b9..558fe40 100644 --- a/Cell.py +++ b/Cell.py @@ -5,6 +5,7 @@ class Cell(): __parent={} __state="dead" __buff="dead" + __original="dead" def __init__(self, item, parent): self.__obj=item @@ -28,18 +29,31 @@ class Cell(): self.__parent.itemconfig(self.__obj, fill="white") - def toggle(self, event): + def toggle(self, event=False): if(self.__state=="live"): self.__state="dead" self.__buff="dead" + self.__original="dead" self.__parent.itemconfig(self.__obj, fill="white") elif(self.__state=="dead"): self.__state="live" self.__buff="live" + self.__original="live" self.__parent.itemconfig(self.__obj, fill="green") def freeze(self): self.__parent.tag_unbind(self.__obj, '') def unfreeze(self): - self.__parent.tag_bind(self.__obj, '', self.toggle) \ No newline at end of file + self.__parent.tag_bind(self.__obj, '', self.toggle) + + def revert(self): + self.__buff=self.__original + self.commit() + self.unfreeze() + + def clear(self): + self.__buff="dead" + self.__original="dead" + self.commit() + self.unfreeze() \ No newline at end of file diff --git a/README.TXT b/README.TXT index 3208e8c..fe44816 100644 --- a/README.TXT +++ b/README.TXT @@ -6,15 +6,16 @@ General Usage Notes ------------------- -Start the program by running the __main__.py file. Eg: python __main__.py -You can specify dimensions by providing width and height as arguments. Eg: python __main__.py 20 20 +-To directly open a file from the command line supply the filename as argument. Example: python __main__.zip . The file must be in Life 1.06 format. -Seed the board by clicking on cells --Click to begin emulation --Open Life 1.06 files by clicking and selecting the file from your computer --Click for emulating the next step --Select the checkbox for automatically running the game +-Click to begin automatic emulation +-Click to stop automatic emulation +-Click to step through a single generation -Click to reset all the cells +-Open Life 1.06 files by clicking and selecting the file from your computer -Save the current pattern to your computer by clicking and choosing the target file to save. --You can specify the cell dimensions by supplying the number of cells in rows and columns respectively as arguments. Example: python life.zip 20 20 --To directly open a file from the command line supply the filename as argument. Example: python life.zip +-Click to go back to the initial pattern from which the current patterns have been generated. +-Click to get a short description of the program. -The program supports Life 1.06 file format only. To use other file formats you need to convert them to Life 1.06 first. Program Notes diff --git a/__main__.py b/__main__.py index 59dab97..e4b4309 100644 --- a/__main__.py +++ b/__main__.py @@ -26,10 +26,10 @@ if(width<10 or depth<10): depth=50 print "Dimensions must be more than 10x10" sys.exit() -elif(width>app.winfo_screenwidth()/10 or depth>app.winfo_screenheight()/10-10): +elif(width>app.winfo_screenwidth()/10 or depth>(app.winfo_screenheight()-150)/10): width=50 depth=50 - print "Dimensions are too large to fit in the screen. Maximum allowed dimension "+str(app.winfo_screenwidth()/10)+"x"+str(app.winfo_screenheight()/10-10) + print "Dimensions are too large to fit in the screen. Maximum allowed dimension "+str(app.winfo_screenwidth()/10)+"x"+str((app.winfo_screenheight()-150)/10) sys.exit() app.render(width, depth) -- 2.39.2