|
| 1 | +import pygame |
| 2 | +import tkinter |
| 3 | +import math # importing modules |
| 4 | +pygame.init() |
| 5 | +num = 0 |
| 6 | +WHITE = (255, 255, 255) |
| 7 | +BLACK = (0, 0, 0) |
| 8 | +GREEN = (0, 255, 0) |
| 9 | +MAUVE = (224, 176, 255) # colour tuples to be used later in the program |
| 10 | +clock = pygame.time.Clock() |
| 11 | + |
| 12 | + |
| 13 | +def get_num(m, n): |
| 14 | + global num |
| 15 | + num = int(n.get()) # gets value of num from Tkinter GUI |
| 16 | + m.destroy() # destroys root window |
| 17 | + |
| 18 | + |
| 19 | +def text_objects(text, font): |
| 20 | + ''' |
| 21 | + Function to create TextSurface and TextRect objects for |
| 22 | + displaying text on the PyGame window. |
| 23 | + It takes 2 parameters: |
| 24 | + text : the text to be displayed |
| 25 | + font : pygame.font.Font object in which the text is to be rendered |
| 26 | + ''' |
| 27 | + textSurface = font.render(text, True, BLACK) |
| 28 | + return textSurface, textSurface.get_rect() |
| 29 | + |
| 30 | + |
| 31 | +def message_display(text, x, y, size): |
| 32 | + ''' |
| 33 | + Function to display the given 'text' message |
| 34 | + at a position of (x,y) in size 'size' |
| 35 | + ''' |
| 36 | + largeText = pygame.font.Font('freesansbold.ttf', size) |
| 37 | + TextSurf, TextRect = text_objects(text, largeText) |
| 38 | + TextRect.center = (x, y) |
| 39 | + display.blit(TextSurf, TextRect) |
| 40 | + pygame.display.update() |
| 41 | + |
| 42 | + |
| 43 | +class Cell: # creating a class for Cell objects on the grid |
| 44 | + def __init__(self, x, y, n): |
| 45 | + self.pos = (x, y) |
| 46 | + self.value = n |
| 47 | + self.highlighted = False |
| 48 | + # adding the number and cell pair to the celldict dictionary |
| 49 | + celldict[self.value] = self |
| 50 | + # display the value of the cell on the grid at the center of the cell |
| 51 | + message_display(f"{self.value}", x + 16, y + 16, 17) |
| 52 | + |
| 53 | + def highlight(self): |
| 54 | + if not self.highlighted: |
| 55 | + x, y = self.pos |
| 56 | + # create a MAUVE rectangle on top of the cell to highlight |
| 57 | + # composite numbers |
| 58 | + pygame.draw.rect(display, MAUVE, (x, y, 32, 32)) |
| 59 | + # rewrite the value of the cell on top of the MAUVE highlight |
| 60 | + message_display(f"{self.value}", x + 16, y + 16, 17) |
| 61 | + # to avoid time to re-highlight cells that have already been |
| 62 | + # highlighted |
| 63 | + self.highlighted = True |
| 64 | + # for the effect of moving highlight or "scanning" the grid |
| 65 | + pygame.time.wait(50) |
| 66 | + |
| 67 | + |
| 68 | +# getting user input from GUI |
| 69 | +m = tkinter.Tk() # root window |
| 70 | +l1 = tkinter.Label(m, text='Enter a number', width=25) # label widget |
| 71 | +n = tkinter.Entry(m) # entry widget |
| 72 | + |
| 73 | +# calculate button bounded to get_num function |
| 74 | +btn = tkinter.Button(m, text='Calculate', command=lambda: get_num(m, n)) |
| 75 | +l1.pack() |
| 76 | +n.pack() |
| 77 | +btn.pack() # using pack() geometry manager |
| 78 | +m.mainloop() # start GUI |
| 79 | + |
| 80 | +# setting up grid |
| 81 | +sq_num = num |
| 82 | +if (math.floor(math.sqrt(num))**2 - num != 0): |
| 83 | + # getting nearest square greater than or equal to num |
| 84 | + sq_num = (math.floor(math.sqrt(num)) + 1)**2 |
| 85 | +dim = int(sq_num**0.5) # number of rows and columns of the window |
| 86 | + |
| 87 | +# creating a window having 'dim' rows and columns. Each cell has width of 32px |
| 88 | +width = 32 * dim |
| 89 | +display = pygame.display.set_mode((width, width)) |
| 90 | +display.fill(WHITE) # fill the display with WHITE color |
| 91 | + |
| 92 | +for i in range(0, width, 32): |
| 93 | + pygame.draw.line(display, BLACK, (i, 0), (i, width) |
| 94 | + ) # drawing row lines 32px apart |
| 95 | +for j in range(0, width, 32): |
| 96 | + # drawing column lines 32px apart |
| 97 | + pygame.draw.line(display, BLACK, (0, j), (width, j)) |
| 98 | +pygame.display.update() |
| 99 | + |
| 100 | +celldict = {} # dictionary to map numbers to their respective cells |
| 101 | + |
| 102 | +count = 1 |
| 103 | +for i in range(0, width, 32): |
| 104 | + # to deal with internal PyGame events in the event queue which cause the |
| 105 | + # system to freeze |
| 106 | + pygame.event.pump() |
| 107 | + for j in range(0, width, 32): |
| 108 | + if (count <= num): |
| 109 | + # create a Cell object at every grid intersection |
| 110 | + cell = Cell(j, i, count) |
| 111 | + clock.tick() |
| 112 | + count += 1 |
| 113 | + else: |
| 114 | + break |
| 115 | +pygame.display.update() |
| 116 | +# Sieving algorithm |
| 117 | +# all the numbers except 1 since 1 is neither prime nor composite |
| 118 | +nums = set(range(2, num + 1)) |
| 119 | +composites = {1} # set of composites detected so far |
| 120 | +celldict[1].highlight() # highlight the Cell 1 |
| 121 | + |
| 122 | +for i in range( |
| 123 | + 2, |
| 124 | + round( |
| 125 | + math.sqrt(num)) + |
| 126 | + 1): # check all numbers till sqrt(num) |
| 127 | + if i not in composites: |
| 128 | + # cross out all the multiples of prime numbers |
| 129 | + comp = [i * k for k in range(2, num // i + 1)] |
| 130 | + composites.update(comp) |
| 131 | + for val in comp: |
| 132 | + pygame.event.pump() |
| 133 | + celldict[val].highlight() # highlight the composites |
| 134 | + |
| 135 | +primetxt = '' # string of primes to be displayed |
| 136 | +for val, cell in celldict.items(): |
| 137 | + pygame.event.pump() |
| 138 | + if not cell.highlighted: # if the cell has not been highlighted |
| 139 | + # it is prime |
| 140 | + x, y = cell.pos |
| 141 | + # highlight the primes with GREEN |
| 142 | + pygame.draw.rect(display, GREEN, (x, y, 32, 32)) |
| 143 | + message_display(f"{val}", x + 16, y + 16, 17) |
| 144 | + pygame.time.wait(100) # to create a moving highlight |
| 145 | + primetxt += str(val) + ' ,' # concatenate primes to primetxt string |
| 146 | + |
| 147 | +# Displaying results using GUI |
| 148 | +m = tkinter.Tk() # root window |
| 149 | +l1 = tkinter.Label(m, text='Primes that were sieved: ') |
| 150 | +# Message widget to display the sieved primes |
| 151 | +msg = tkinter.Message(m, text=primetxt[:-1], width=200) |
| 152 | +l1.pack() |
| 153 | +msg.pack() |
| 154 | +m.mainloop() |
0 commit comments