diff --git a/02_gameOfLife/Main.py b/02_gameOfLife/Main.py old mode 100755 new mode 100644 index db9fbb8..6bb2700 --- a/02_gameOfLife/Main.py +++ b/02_gameOfLife/Main.py @@ -2,31 +2,25 @@ import pygame import random from OpenGL.GL import * +from OpenGL.GLU import * from pygame.locals import * -import argparse - -#TODO: remove global vars +video_flags = OPENGL | HWSURFACE | DOUBLEBUF | FULLSCREEN pygame.init() -window_w = 1600 -window_h = 900 +dinfo = pygame.display.Info(); -livingSpaceWidth = 64 -livingSpaceHeight = 36 +livingSpaceWidth = 48 +livingSpaceHeight = 27 -creatureW = window_w/(livingSpaceWidth) -creatureH = window_h/(livingSpaceHeight) +creatureW = dinfo.current_w/(livingSpaceWidth) +creatureH = dinfo.current_h/(livingSpaceHeight) -FPS = 30 +FPS = 40 livingSpace = [] -draw_buffer = [] -draw_buffer_old = [] - - def resize(shape): width, height = shape if height == 0: @@ -54,34 +48,30 @@ def isAlive(x,y): return livingSpace[x][y] == 1000 def draw(): - global draw_buffer - global draw_buffer_old - #glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslatef(0.0,0.0,3.0) glBegin(GL_QUADS) - for column, row in draw_buffer + draw_buffer_old: - if livingSpace[column][row] != 0: - health = float(float(livingSpace[column][row])/1000.0) + for column in range(livingSpaceWidth): + for row in range(livingSpaceHeight): + if livingSpace[column][row] != 0: + health = float(float(livingSpace[column][row])/1000.0) - glColor4f(health*(float(column)/float(livingSpaceWidth)), - health*(float(livingSpaceWidth-column)/float(livingSpaceWidth)), - health*(float(row)/float(livingSpaceHeight)),1.0) - x = column * creatureW - y = row * creatureH + glColor4f(health*(float(column)/float(livingSpaceWidth)), + health*(float(livingSpaceWidth-column)/float(livingSpaceWidth)), + health*(float(row)/float(livingSpaceHeight)),1.0) + x = column * creatureW + y = row * creatureH - glVertex3f(x,y,0.0) - glVertex3f(x + creatureW-1.0,y,0.0) - glVertex3f(x+creatureW-1,y+creatureH-1,0.0) - glVertex3f(x,y+creatureH-1,0.0) + glVertex3f(x,y,0.0) + glVertex3f(x + creatureW-1.0,y,0.0) + glVertex3f(x+creatureW-1,y+creatureH-1,0.0) + glVertex3f(x,y+creatureH-1,0.0) glEnd() - draw_buffer_old = draw_buffer - draw_buffer = [] - def getNeighborCount(x,y): count = 0 @@ -104,7 +94,6 @@ def getNeighborCount(x,y): return count def calculateNextGeneration(): - neighborCount = [] for column in range(livingSpaceWidth): neighborCount.append([]) @@ -116,82 +105,26 @@ def calculateNextGeneration(): if 2 <= neighborCount[column][row] <= 3: if neighborCount[column][row] == 3: livingSpace[column][row] = 1000 - draw_buffer.append((column, row)) if not isAlive(column,row): livingSpace[column][row] = float(livingSpace[column][row])/1.2 - draw_buffer.append((column, row)) else: livingSpace[column][row] = float(livingSpace[column][row])/1.2 - draw_buffer.append((column, row)) if livingSpace[column][row] < 20: livingSpace[column][row] = 0 def main(): - global livingSpaceWidth - global livingSpaceHeight - global creatureW - global creatureH - global window_w - global window_h - # parsing args: - parser = argparse.ArgumentParser(description="game of life") - parser.add_argument('--steps', dest='steps', default = 20 , help='steps per second') - parser.add_argument('--w', dest='w', default = livingSpaceWidth, help = 'field width') - parser.add_argument('--h', dest='h', default=livingSpaceHeight, help = 'field height') - #parser.add_argument('--calc', dest='calc', default=0, help='calculate steps and only display result') - #parser.add_argument('--default', dest='default', default=0, help='setting all fields to this value') - parser.add_argument('--fullscreen', dest='fullscreen', action='store_true') - parser.add_argument('--window_w', dest='win_w', default=window_w, help='window width') - parser.add_argument('--window_h', dest='win_h', default=window_h, help='window height') - parser.add_argument('--configurator', dest='configurator', action='store_true', help='start in field edit mode') - #parser.add_argument('--code', dest='code', default='01', help='binary code for the ant (\'01\' corresponds to the starndard ant behaviour)') - - parser.set_defaults(fullscreen=False) - parser.set_defaults(configurator=False) - - args = parser.parse_args() - steps_per_sec = int(args.steps) - livingSpaceWidth = int(args.w) - livingSpaceHeight = int(args.h) - - video_flags = OPENGL | HWSURFACE | DOUBLEBUF - - - if args.fullscreen: - video_flags = OPENGL | HWSURFACE | DOUBLEBUF | FULLSCREEN - dinfo = pygame.display.Info() - window_w = dinfo.current_w - window_h = dinfo.current_h - else: - window_w = int(args.win_w) - window_h = int(args.win_h) - - - creatureW = window_w / (livingSpaceWidth) - creatureH = window_h / (livingSpaceHeight) - - #antPosition = (livingSpaceWidth // 2, livingSpaceHeight // 2) - - - pygame.display.set_mode((window_w,window_h),video_flags) + pygame.display.set_mode((dinfo.current_w,dinfo.current_h),video_flags) initLivingSpace() - - resize((window_w, window_h)) + resize((dinfo.current_w,dinfo.current_h)) init() clock = pygame.time.Clock() frames = 0 - counter = 0 - logic_frame_pause = FPS / steps_per_sec - configurator_mode = bool(args.configurator) - - field_draws = 0 - #Hauptschleife: while True: @@ -203,53 +136,11 @@ def main(): if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): break + draw() - field_draws += len(draw_buffer) + len(draw_buffer_old) - frames += 1 - - if frames % FPS == 0: - print("average field draws per frame: " + str(field_draws / FPS)) - field_draws = 0 - pygame.display.flip() - - if configurator_mode: - # move with keys: - if event.type == KEYDOWN: - # draw_buffer.append((antPosition[0],antPosition[1])) - # if event.key == K_DOWN: - # move_ant(0,+1) - # elif event.key == K_UP: - # move_ant(0,-1) - # elif event.key == K_LEFT: - # move_ant(-1,0) - # elif event.key == K_RIGHT: - # move_ant(+1,0) - # elif event.key == K_SPACE: - # new_key = (livingSpace[antPosition[0]][antPosition[1]]) % num_colors + 1 - # if not isAlive(antPosition[0], antPosition[1]): - # new_key += 1 - # activate(antPosition[0], antPosition[1], new_key) - # elif event.key == K_BACKSPACE: - # deactivate(antPosition[0],antPosition[1]) - if event.key == K_RETURN: - configurator_mode = False - - counter += 1 - - if logic_frame_pause >= 1: - if counter > logic_frame_pause: - calculateNextGeneration() - counter = 0 - else: - # multiple calculations per frame: - for i in range(int(1 / logic_frame_pause)): - calculateNextGeneration() - - # switch to configurator mode: - if event.type == KEYDOWN and event.key == K_RETURN: - configurator_mode = True + calculateNextGeneration() diff --git a/langton/Main.py b/langton/Main.py index a0664c3..df8dcb8 100755 --- a/langton/Main.py +++ b/langton/Main.py @@ -1,9 +1,13 @@ #!/usr/bin/env python3 + import pygame from OpenGL.GL import * from pygame.locals import * import argparse +import sys +import random +import time #TODO: remove global vars @@ -42,6 +46,9 @@ num_colors = 2 color_list = [] code = [False,True] +# store number of active cells +num_active_cells = 0 + # helper function for colors: def HSVtoRGB(h,s,v): c = v*s @@ -144,10 +151,10 @@ def draw(): glColor4f(1,1,1,0.5) - glVertex3f(x + offX, y, 0.0) - glVertex3f(x + creatureW - 1, y + offY, 0.0) - glVertex3f(x + offX, y + creatureH - 1, 0.0) - glVertex3f(x, y + offY, 0.0) + glVertex3f(x + offX, y, 0.0) if antRotation != SOUTH else glVertex3f(x + offX, y + creatureH/2, 0.0) + glVertex3f(x + creatureW - 1, y + offY, 0.0) if antRotation != WEST else glVertex3f(x + creatureW/2, y + offY, 0.0) + glVertex3f(x + offX, y + creatureH - 1, 0.0) if antRotation != NORTH else glVertex3f(x + offX, y + creatureH/2, 0.0) + glVertex3f(x, y + offY, 0.0) if antRotation != EAST else glVertex3f(x + creatureW/2, y + offY, 0.0) glEnd() @@ -156,6 +163,10 @@ def draw(): def activate(i,j,key = 1): + global num_active_cells + if livingSpace[i][j] == 0: + num_active_cells += 1 + livingSpace[i][j] = key if num_colors > 2: livingSpaceColor[i][j] = [ @@ -169,6 +180,9 @@ def activate(i,j,key = 1): update_queue.append((i,j)) def deactivate(i,j): + global num_active_cells + if livingSpace[i][j] != 0: + num_active_cells -= 1 livingSpace[i][j] = 0 # correct color: livingSpaceColor[i][j] = [ @@ -282,6 +296,7 @@ def main(): global creatureW global creatureH global antPosition + global antRotation global window_w global window_h global color_list @@ -289,17 +304,25 @@ def main(): global code # parsing args: - parser = argparse.ArgumentParser(description="langton's ant") + parser = argparse.ArgumentParser(description="langton's ant simulation tool", formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('--steps', dest='steps', default = 20 , help='steps per second') parser.add_argument('--w', dest='w', default = livingSpaceWidth, help = 'field width') parser.add_argument('--h', dest='h', default=livingSpaceHeight, help = 'field height') parser.add_argument('--calc', dest='calc', default=0, help='calculate steps and only display result') - parser.add_argument('--default', dest='default', default=0, help='setting all fields to this value') parser.add_argument('--fullscreen', dest='fullscreen', action='store_true') parser.add_argument('--window_w', dest='win_w', default=window_w, help='window width') parser.add_argument('--window_h', dest='win_h', default=window_h, help='window height') parser.add_argument('--configurator', dest='configurator', action='store_true', help='start in field edit mode') parser.add_argument('--code', dest='code', default='01', help='binary code for the ant (\'01\' corresponds to the starndard ant behaviour)') + parser.add_argument('--file', dest='file', default='', help='writing number of living cells per step in this file') + parser.add_argument('--pattern', dest='pattern', default='0', + help='initial pattern for the field. Possible values:\n' + + '\t * 0: all fields inactive\n' + + '\t * 1: all fields active\n' + + '\t * check: checkboard pattern\n' + + '\t * horizontal: horizontal stripes\n' + + '\t * vertical: vertical stripes\n' + + '\t * random: random values\n') parser.set_defaults(fullscreen=False) parser.set_defaults(configurator=False) @@ -309,6 +332,10 @@ def main(): livingSpaceWidth = int(args.w) livingSpaceHeight = int(args.h) calc = int(args.calc) + filename = args.file + fileobj = None + if len(filename) > 0: + fileobj = open(filename, mode='w') video_flags = OPENGL | HWSURFACE | DOUBLEBUF @@ -345,11 +372,6 @@ def main(): initLivingSpace() - if int(args.default) != 0: - for i in range(livingSpaceWidth): - for j in range(livingSpaceHeight): - activate(i,j) - resize((window_w, window_h)) init() @@ -362,9 +384,52 @@ def main(): field_draws = 0 + # apply pattern + if args.pattern == '0': + # nothing to do + pass + elif args.pattern == '1': + for i in range(livingSpaceWidth): + for j in range(livingSpaceHeight): + activate(i,j) + elif args.pattern == 'check': + for i in range(livingSpaceWidth): + for j in range(livingSpaceHeight): + if (i + j) % 2 == 0: + activate(i,j) + elif args.pattern == 'horizontal': + for i in range(livingSpaceWidth): + for j in range(livingSpaceHeight): + m = j % num_colors + if num_colors > 2: + m += 1 + if m != 0: + activate(i,j,m) + elif args.pattern == 'vertical': + for i in range(livingSpaceWidth): + for j in range(livingSpaceHeight): + m = i % num_colors + if num_colors > 2: + m += 1 + if m != 0: + activate(i,j,m) + elif args.pattern == 'random': + r = random.Random(time.time()) + for i in range(livingSpaceWidth): + for j in range(livingSpaceHeight): + k = r.randint(0,num_colors - 1) + if num_colors > 2: + k += 1 + if k != 0: + activate(i,j,k) + else: + print("error. unknown pattern") + parser.print_help() + sys.exit(-1) + if (calc > 0): for i in range(calc): - update_ant(); + update_ant() #main loop: while True: @@ -376,7 +441,7 @@ def main(): if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): break - update_field(); + update_field() draw() field_draws += len(draw_buffer) + len(draw_buffer_old) @@ -408,6 +473,12 @@ def main(): activate(antPosition[0], antPosition[1], new_key) elif event.key == K_BACKSPACE: deactivate(antPosition[0],antPosition[1]) + elif event.key == K_LCTRL: + antRotation = (antRotation - 1) % 4 + move_ant(0,0) + elif event.key == K_RCTRL: + antRotation = (antRotation + 1) % 4 + move_ant(0,0) elif event.key == K_RETURN: configurator_mode = False @@ -419,15 +490,21 @@ def main(): if logic_frame_pause >= 1: if counter > logic_frame_pause: update_ant() + if fileobj != None: + fileobj.write(str(num_active_cells) + '\n') counter = 0 else: # multiple calculations per frame: for i in range(int(1 / logic_frame_pause)): update_ant() + if fileobj != None: + fileobj.write(str(num_active_cells) + '\n') # switch to configurator mode: if event.type == KEYDOWN and event.key == K_RETURN: configurator_mode = True + if fileobj != None: + fileobj.close() if __name__ == '__main__': diff --git a/langton/README.md b/langton/README.md index c991431..40db0bf 100644 --- a/langton/README.md +++ b/langton/README.md @@ -2,10 +2,10 @@ ``` usage: Main.py [-h] [--steps STEPS] [--w W] [--h H] [--calc CALC] - [--default DEFAULT] [--fullscreen] [--window_w WIN_W] - [--window_h WIN_H] [--configurator] [--code CODE] + [--fullscreen] [--window_w WIN_W] [--window_h WIN_H] + [--configurator] [--code CODE] [--pattern PATTERN] -langton's ant +langton's ant simulation tool optional arguments: -h, --help show this help message and exit @@ -13,23 +13,29 @@ optional arguments: --w W field width --h H field height --calc CALC calculate steps and only display result - --default DEFAULT setting all fields to this value --fullscreen --window_w WIN_W window width --window_h WIN_H window height --configurator start in field edit mode - --code CODE binary code for the ant ('01' corresponds to the - starndard ant behaviour) + --code CODE binary code for the ant ('01' corresponds to the starndard ant behaviour) + --pattern PATTERN initial pattern for the field. Possible values: + * 0: all fields inactive + * 1: all fields active + * check: checkboard pattern + * horizontal: horizontal stripes + * vertical: vertical stripes + * random: random values ``` -configuration mode keys: +keys: -| key | function | -| ---------- | -------------------------------------- | -| return | enter/leave configuration mode | -| arrow keys | move langton's ant | -| space | activate field or switch field's color | -| backspace | deactivate field | -| escape | exit program | +| key | function | +| ---------------------- | ---------------------------------------- | +| return | enter/leave configuration mode | +| arrow keys | move langton's ant (in configuration mode) | +| space | activate field or switch field's color (in configuration mode) | +| backspace | deactivate field (in configuration mode) | +| ctrl left / ctrl right | rotate ant (in configuration mode) | +| escape | exit program |