CSC231 Developing the Game of Life in Assembly

From dftwiki3
Jump to: navigation, search

--D. Thiebaut (talk) 12:25, 27 March 2017 (EDT)


Python Program Developed in Class (3/27/17)


Source


dish = [ ' ', ' ', ' ', ' ', ' ', '#', ' ', '#', ' ', '#',
         ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#',
         ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#',
         ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#',
         ' ', '#', ' ', '#', ' ', '#', ' ', ' ', ' ', ' ', ' ' ]

newGen = [' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#',
         ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#',
         ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#',
         ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#',
         ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ' ]

N = len( dish )

# applies the rules of life to the array dish,
# and stores the result in the array newGen, which
# is returned.  N is the number of cells.
def life( dish, N ):
    newGen = [' '] * N

    # loop through all the cells
    for i in range( 1, N-1 ):
        # look at fate of cell
        neighbors = 0
        if dish[i-1] == '#': neighbors += 1
        if dish[i+1] == '#': neighbors += 1

        if neighbors == 1:
            newGen[i] = '#'
        else:
            newGen[i] = ' '
        
        
    return newGen


def main():
    global dish, newGen, N
    maxGen = 20

    print( "".join( dish ) )
    
    # loop through generations
    for generation in range( maxGen ):

        newGen = life( dish, N )
        # display new generation
        print( "".join( newGen ) )

        # future becomes the present
        dish = newGen

        
main()


Output


     # # # # # # # # # # # # # # # # # # # # #     
    #                                         #    
   # #                                       # #   
  #   #                                     #   #  
 # # # #                                   # # # # 
        #                                 #        
       # #                               # #       
      #   #                             #   #      
     # # # #                           # # # #     
    #       #                         #       #    
   # #     # #                       # #     # #   
  #   #   #   #                     #   #   #   #  
 # # # # # # # #                   # # # # # # # # 
                #                 #                
               # #               # #               
              #   #             #   #              
             # # # #           # # # #             
            #       #         #       #            
           # #     # #       # #     # #           
          #   #   #   #     #   #   #   #          
         # # # # # # # #   # # # # # # # #


Python Program, Version 2


This program uses no tests, and a couple of programming tricks provided by students in class.

# gameOfLife.py
# D. Thiebaut
# 1-Dimensional Game of Life where cells are maintained
# as arrays of 0s and 1s.  0 means dead, 1 means alive.
#
# This program uses a neat trick provided by Artemis
# in class, which recognizes that the fate of a
# cell is equal to the xor of its neighbors.
# two live neighbors correspond to 1 xor 1 = 0.  Cell dies.
# two dead neighbors correspond to 0 xor 0 = 0.  Cell dies.
# only one neighbor alive corresponds to 0 xor 1 = 1.  Cell lives.
# The other neat trick offered by Emma is to add space (' ')
# to the value of a cell before printing.  If a cell is dead,
# adding 0 to ' ' makes it a space. Adding 1 to ' ' makes it '!'

from __future__ import print_function
from __future__ import division

def life( dish, N ):
    newGen = [0]*N
    for i in range( 1, N-1 ):
        fate = dish[i-1] ^ dish[i+1] # ^ is xor
        newGen[i] = fate 
    return newGen

def printDish( dish ):
    #print( "".join( [ str(chr(ord(' ') + c)) for c in dish] ) )
    for x in dish:
        s = str( chr( ord(' ') + x ) )
        print( s, sep="", end="" )
    print()
                 
def main():
    N = 40
    dish = (N//2-10)*[1] + 10*[0,1] + (N//2-10)*[0]
    dish = dish[0:N]
    
    printDish( dish ) # print first generation 

    # repeat, for some number of generations
    for generation in range( 20 ):
        newGen = life( dish, N )
        printDish( newGen )
        dish = newGen

main()


Output


!!!!!!!!!! ! ! ! ! ! ! ! ! ! !          
         !                    !         
        ! !                  ! !        
       !   !                !   !       
      ! ! ! !              ! ! ! !      
     !       !            !       !     
    ! !     ! !          ! !     ! !    
   !   !   !   !        !   !   !   !   
  ! ! ! ! ! ! ! !      ! ! ! ! ! ! ! !  
 !               !    !               ! 
  !             ! !  ! !             !  
 ! !           !   !!   !           ! ! 
    !         ! ! !!!! ! !         !    
   ! !       !    !  !    !       ! !   
  !   !     ! !  ! !! !  ! !     !   !  
 ! ! ! !   !   !!  !!  !!   !   ! ! ! ! 
        ! ! ! !!!!!!!!!!!! ! ! !        
       !      !          !      !       
      ! !    ! !        ! !    ! !      
     !   !  !   !      !   !  !   !     
    ! ! ! !! ! ! !    ! ! ! !! ! ! !


Assembly


Note, at the time we created this program, we didn't have available to us tests or functions, which makes the code slightly more complicated than needed.

Version


Source


;;; ; GameOfLife.asm
;;; ; Authors: D. Thiebaut and CSC231 Class
;;; ;
;;; ; Implements a 1-dimensional version of 
;;; ; Conway's Game of life.
;;; ; Note that because we do not "know" yet
;;; ; how to test or to use functions, the code
;;; ; is not as efficient as it could be.
;;; ;
;;; ; to assemble and run:
;;; ;
;;; ;     nasm -f elf -F  stabs GameOfLife.asm
;;; ;     ld -melf_i386 -o GameOfLife GameOfLife.o
;;; ;     ./GameOfLife
;;; ; -------------------------------------------------------------------


;;;  ------------------------------------------------------------
;;;  data areas
;;;  ------------------------------------------------------------

	        section .data
;;; the current dish with its cells.  We use 0 and 1 to
;;; indicate dead and live cells, respectively.
dish            db      0,0,0,1,1,1,0,1,0,1,0,1,0,1
		db	0,1,0,1,0,1,0,1
		db	0,1,0,1,0,1,0,1
		db	0,1,0,1,0,1,0,1
		db	0,1,0,1,0,1,0,1,0,0,0,0,0
N		equ	$-dish			; The number of cells
						;  in the dish

;;; the new generation of cells.  That's the "future" of the
;;; cells in the dish.  We make it the same size as dish, and
;;; fill it with N dead cells.
	
newGen	        times N db 0
	
;;; dishP is a string that will contain ' ' or '!' for
;;; each 0 or 1 in dish.  
dishP		times N db ' '
		db	10			; add a \n at the end
						;  of dishP
	
maxGen		dd	20			; the max number of
						; generations
generation	dd	0			; save ecx from for generation loop
	
;;;  ------------------------------------------------------------
;;;  code area
;;;  ------------------------------------------------------------

	        section .text
	        global  _start

_start:
main:	
;;; -------------------------------------------------------------
;;; print( dish )
		;; first we copy dish into dishP and at the same
		;; time replace 0 by ' ' and 1 by '!'
		mov	ecx, N			;for each byte in dish
		mov	esi, dish		;esi points to source
		mov	edi, dishP
forPrint:	mov	al, byte[esi]
		add	al, ' '			;0 becomes ' ', 1 becomes '!'
		mov	byte[edi], al
		inc	esi			;esi points to next byte in dish
		inc	edi			;edi points to next byte in dispP
		loop	forPrint

		;; print dishP as a string.
		mov	eax, 4			;prints dishP to screen
		mov	ebx, 1
		mov	ecx, dishP 		;dishP address
		mov	edx, N+1		;+1 to include the \n
		int	0x80

;;; -----------------------------------------------------------
;;; for generation in range( 20 ):

		mov	ecx, 20			;get ready to loop 20 times

forGen:		mov	dword[generation],ecx	;save ecx in generation temp var

;;; -----------------------------------------------------------
;;;      newGen = life( dish, N )
;;; 	 newGen[0] = 0
;;; 	 newGen[N-1] = 0

	        mov    byte[newGen], 0
		mov    byte[newGen+N-1], 0

;;; -----------------------------------------------------------
;;;      for i in range( 1, N-1 ):

	        mov    ecx, N-2
	        mov    esi, dish+1
	        mov    edi, newGen+1
forLife:	
	
;;; -----------------------------------------------------------
;;; 	     fate = dish[i-1] ^ dish[i+1]
;;; 	     newGen[i] = fate
		mov	al, byte[esi-1]
	        xor     al, byte[esi+1]
	        mov	byte[edi], al
		inc	esi
		inc	edi
		loop 	forLife

;;; -----------------------------------------------------------
;;;     dish = newGen

	        mov	ecx, N
		mov	esi, newGen
		mov	edi, dish
forMove:	mov	al, byte[esi] 	;copy newGen[i] to dish[i]
		mov	byte[edi], al
		inc	esi
		inc	edi
		loop	forMove

;;; -----------------------------------------------------------
;;;     print( dish )

		;; first we copy dish into dishP and at the same
		;; time replace 0 by ' ' and 1 by '!'
		mov	ecx, N			;for each byte in dish
		mov	esi, dish		;esi points to source
		mov	edi, dishP
forPrint2:	mov	al, byte[esi]
		add	al, ' '			;0 becomes ' ', 1 becomes '!'
		mov	byte[edi], al
		inc	esi			;esi points to next byte in dish
		inc	edi			;edi points to next byte in dispP
		loop	forPrint2

		;; print dishP as a string.
		mov	eax, 4			;prints dishP to screen
		mov	ebx, 1
		mov	ecx, dishP 		;dishP address
		mov	edx, N+1		;+1 to include the \n
		int	0x80
	
;;; ready to loop back to forGen
		mov	ecx,dword[generation]
		loop	forGen
	
;;;  exit()

	        mov     eax,1
	        mov     ebx,0
	        int     0x80	; final system call

Output


   !!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !     
  !! !                                        !    
 !!!  !                                      ! !   
 ! !!! !                                    !   !  
   ! !  !                                  ! ! ! ! 
  !   !! !                                !        
 ! ! !!!  !                              ! !       
     ! !!! !                            !   !      
    !  ! !  !                          ! ! ! !     
   ! !!   !! !                        !       !    
  !  !!! !!!  !                      ! !     ! !   
 ! !!! ! ! !!! !                    !   !   !   !  
   ! !     ! !  !                  ! ! ! ! ! ! ! ! 
  !   !   !   !! !                !                
 ! ! ! ! ! ! !!!  !              ! !               
             ! !!! !            !   !              
            !  ! !  !          ! ! ! !             
           ! !!   !! !        !       !            
          !  !!! !!!  !      ! !     ! !           
         ! !!! ! ! !!! !    !   !   !   !          
        !  ! !     ! !  !  ! ! ! ! ! ! ! !