Automatic Wordle Solver with Python and Turtle (Source Code Included)

Wordle is a very popular puzzle game. Here is the source code that automatically solves the wordle problems. There isn’t too much trick. This code just randomly picks a valid word. Click on the letters to match the colors on wordle and then hit enter. This program will automatically guess new words until the word has been guessed correctly.

import random
import turtle
from tkinter import * 
from tkinter import messagebox

screen = turtle.Screen()
screen.setup(1000,1000)
screen.title("Wordle Solver - PythonTurtle.Academy")
turtle.speed(0)
turtle.hideturtle()
screen.tracer(0,0)
screen.bgcolor('black')
turtle.color('white')

gs = 0
state = []
for i in range(6):
  state.append([-1]*5)

def getwords(words, cs, count=False):
  res = []
  cnt = 0
  for w in words:
    t = list(w)
    flag = True
    cnt = dict()
    # first loop checks only positions are set
    for l,p in cs:
      if p<0: continue
      if cs[(l,p)] > 0:
        if t[p] == l:
          t[p] = '*'
          if l in cnt: cnt[l] += 1
          else: cnt[l] = 1
        else:
          flag = False
          break
      else:
      	if t[p] == l:
      		flag = False
      		break
    if (not flag): continue
    # second loop checks only positions are not set
    for l,p in cs:
      if p!=-1: continue
      v = 0 if l not in cnt else cnt[l]
      for _ in range(cs[(l,p)]-v):
      	try:
      		p = t.index(l)
      		t[p] = '*'
      	except ValueError:
      		flag = False
      		break
      if (not flag): break
    if (not flag): continue
    # third loops checks non-existent letter
    for l,p in cs:
      if p!=-2: continue
      if l in t:
        flag = False
        break
    
    if flag: 
    	if count: cnt += 1
    	else: res.append(w)
  if count: return cnt
  else: return res

def guess_random(words):
  return random.choice(words)
		
def draw_square(coord,s,fc='black'):
  turtle.up()
  x = coord[0]
  y = coord[1]
  turtle.goto(x-s/2,y-s/2)
  turtle.seth(0)
  turtle.down()
  turtle.fillcolor(fc)
  turtle.begin_fill()
  for _ in range(4):
    turtle.fd(s)
    turtle.left(90)
  turtle.end_fill()

def get_coord(i,j):
  return -200+100*j, 300-100*i

def draw_board():
  turtle.pencolor('dark gray')
  for i in range(6):
    for j in range(5):
      draw_square(get_coord(i,j),80)

def display_word(w):
  turtle.up()
  turtle.color('white')
  for i in range(5):
    x,y = get_coord(gs,i)
    turtle.goto(x,y-23)
    turtle.write(w[i].upper(),align='center',font=('Arial',40,'bold'))

def update_cell(i,j):
  global w,state
  x, y = get_coord(i,j)
  turtle.pencolor('dark gray')
  if state[i][j] == 0:
    fc = 'dark gray'
  elif state[i][j] == 1:
    fc = 'goldenrod'
  else: fc = 'green'
  draw_square(get_coord(i,j),80,fc)
  turtle.up()
  turtle.color('white')
  turtle.goto(x,y-23)
  turtle.write(w[j].upper(),align='center',font=('Arial',40,'bold'))
  screen.update()
  
def play(x,y):
  flag = False
  for i in range(6):
    if flag: break
    for j in range(5):
      cx, cy = get_coord(i,j)
      if (cx-x)**2 + (cy-y)**2 < 1600:
        flag = True
        ci = i
        cj = j
        break
  if not flag: return
  if ci != gs: return
  state[ci][cj] = (state[ci][cj] + 1) % 3
  update_cell(ci,cj)

def submit():
  global state
  global gs
  global w,words

  for i in range(5):
    if state[gs][i] == -1: return

  cs = dict()
  for i in range(5):
    if state[gs][i] == 0: # letter doesn't exist
      cs[(w[i],-2)] = 1
    else:
      if (w[i],-1) not in cs:
        cs[(w[i],-1)] = 1
      else:
        cs[(w[i],-1)] += 1
      if state[gs][i] == 1: cs[(w[i],i)] = 0
      else: cs[(w[i],i)] = 1
  words = getwords(words,cs)
  print(len(words))
  w = guess_random(words)
  gs += 1
  display_word(w)
  if len(words) == 1:
    messagebox.showinfo("Done", "Congratulations!")
    turtle.bye()

  screen.update()

orig_words = []
f = open('wordle_words.txt','r')
for w in f:
  orig_words.append(w.strip())

cs = dict()
words = getwords(orig_words,cs)
w = guess_random(words)
w = 'tesla'
draw_board()
display_word(w)
screen.update()
screen.onclick(play)
screen.onkey(submit, 'Return')
screen.listen()
screen.mainloop()

You will also need to download a list of words as ‘wordle_words.txt’.

Typing Game with Python and Turtle (Source Code Included)

Develop a typing game to improve keyboard skill as demonstrated in the following YouTube video.

Typing Game with Python and Turtle

At any moment ten random letters fall from the top of screen. When you hit a correct letter from keyboard, that letter disappears and is replaced by a new random letter dropping from the top. Also, your score will increase by 1. When you hit an incorrect letter, your score will decrease by 1.

Make these letters fall at random speeds and also let the speed increase gradually as time progresses. The game will end when a letter falls to the bottom of the screen.

You will need to use Turtle’s ontimer() and onkey() events to implement this project.

Source Code:

import turtle
import random

screen = turtle.Screen()
screen.setup(1000,1000)
screen.title('Typing Game - PythonTurtle.Academy')
screen.bgcolor('blue')
screen.tracer(0,0)
turtle.hideturtle()
turtle.up()
turtle.color('red')
score_turtle = turtle.Turtle()
score_turtle.color('red')
score_turtle.up()
score_turtle.hideturtle()
turtle.goto(350,400)
turtle.write('Score: ', align='center', font=('Courier',25,'normal'))

min_speed = 5
max_speed = 30
letters = []
speeds = []
pos = []
lts = []
n = 10
game_over = False
score = 0

def increase_difficulty():
    global min_speed, max_speed
    min_speed += 1
    max_speed += 1
    screen.ontimer(increase_difficulty,5000)

def draw_game_over():
    turtle.goto(0,0)
    turtle.color('red')
    turtle.write('GAME OVER', align='center', font=('Courier',50,'normal'))
    turtle.goto(0,-150)
    turtle.color('orange')
    turtle.write('Your Score is {}'.format(score), align='center', font=('Courier',40,'normal'))
    screen.update()

def draw_score():
    score_turtle.clear()
    score_turtle.goto(420,400)
    score_turtle.write('{}'.format(score),align='center',font=('Courier',25,'normal'))
    screen.update()
    
def draw_letters():
    global game_over
    for i in range(len(letters)):
        lts[i].clear()
        lts[i].goto(pos[i])
        lts[i].write(letters[i],align='center',font=('courier',20,'normal'))
        pos[i][1] -= speeds[i]
        if pos[i][1]<-500:
            game_over = True
            draw_game_over()
            return
    screen.update()
    screen.ontimer(draw_letters,50)

def f(c): # handle keyboard press
    global score
    if c in letters:
        score += 1
        k = letters.index(c)
        while True:
            l = chr(ord('a')+random.randrange(26))
            if l not in letters:
                letters[k] = l
                break            
        pos[k] = [random.randint(-450,450),500]        
        speeds[k] = random.randint(min_speed,max_speed)
    else: score -= 1
    draw_score()
        
for _ in range(n):
    lts.append(turtle.Turtle())
    while True:
        l = chr(ord('a')+random.randrange(26))
        if l not in letters:
            letters.append(l)
            break
    speeds.append(random.randint(min_speed,max_speed))
    pos.append([random.randint(-450,450),500])
    
for i in range(n):
    lts[i].speed(0)
    lts[i].hideturtle()
    lts[i].up()
    lts[i].color('yellow')
    
draw_letters()
increase_difficulty()

screen.onkey(lambda: f('a'), 'a')
screen.onkey(lambda: f('b'), 'b')
screen.onkey(lambda: f('c'), 'c')
screen.onkey(lambda: f('d'), 'd')
screen.onkey(lambda: f('e'), 'e')
screen.onkey(lambda: f('f'), 'f')
screen.onkey(lambda: f('g'), 'g')
screen.onkey(lambda: f('h'), 'h')
screen.onkey(lambda: f('i'), 'i')
screen.onkey(lambda: f('j'), 'j')
screen.onkey(lambda: f('k'), 'k')
screen.onkey(lambda: f('l'), 'l')
screen.onkey(lambda: f('m'), 'm')
screen.onkey(lambda: f('n'), 'n')
screen.onkey(lambda: f('o'), 'o')
screen.onkey(lambda: f('p'), 'p')
screen.onkey(lambda: f('q'), 'q')
screen.onkey(lambda: f('r'), 'r')
screen.onkey(lambda: f('s'), 's')
screen.onkey(lambda: f('t'), 't')
screen.onkey(lambda: f('u'), 'u')
screen.onkey(lambda: f('v'), 'v')
screen.onkey(lambda: f('w'), 'w')
screen.onkey(lambda: f('x'), 'x')
screen.onkey(lambda: f('y'), 'y')
screen.onkey(lambda: f('z'), 'z')

screen.listen()
screen.mainloop()

Tutorial: Conway’s Game of Life with Python Turtle

In this tutorial, we are you going show how to implement Conway’s Game of Life simulation with Python Turtle.

Conway’s Game of Life with Python Turtle

Step 1. Drawing The Grid

This step should be straightforward. We just need n horizontal and n vertical lines centered in the screen. The following is the code snippet that draws the grid.

screen=turtle.Screen()
turtle.setup(1000,1000)
turtle.title("Conway's Game of Life - PythonTurtle.Academy")
turtle.hideturtle()
turtle.speed(0)
turtle.tracer(0,0)

n = 50 # nxn grid
def draw_line(x1,y1,x2,y2): # this function draw a line between x1,y1 and x2,y2
    turtle.up()
    turtle.goto(x1,y1)
    turtle.down()
    turtle.goto(x2,y2)
    
def draw_grid(): # this function draws nxn grid
    turtle.pencolor('gray')
    turtle.pensize(3)
    x = -400
    for i in range(n+1):
        draw_line(x,-400,x,400)
        x += 800/n
    y = -400
    for i in range(n+1):
        draw_line(-400,y,400,y)
        y += 800/n

draw_grid()
screen.update()

It should a grid like the following picture:

n x n grid

Step 2: Creating Life

We need data structure to store the lives in the n x n cells. The natural data structure for this purpose is a list of lists. We are going to use value 1 to represent ‘life’ and 0 to represent ‘no life’. The lives in cells will be randomly generated with 1/7 probability of having life. The following is the code snippet that creates and initializes lives:

life = list() # create an empty list
def init_lives():
    for i in range(n):
        liferow = [] # a row of lives
        for j in range(n):
            if random.randint(0,7) == 0: # 1/7 probability of life
                liferow.append(1) # 1 means life
            else:
                liferow.append(0) # 0 means no life
        life.append(liferow) # add a row to the life list -> life is a list of list

Step 3: Displaying Life in Cells

The next task is to draw live cells in the grid. We will create and use a new turtle called lifeturtle to draw the live cells. Because cells can become alive or dead, we need to erase them and redraw in each cycle. However, there is no need to erase the grid. By just clearing the lifeturtle, there is no need to redraw the grid. The following is complete code for the first 3 steps.

import turtle
import random

screen=turtle.Screen()
turtle.setup(1000,1000)
turtle.title("Conway's Game of Life - PythonTurtle.Academy")
turtle.hideturtle()
turtle.speed(0)
turtle.tracer(0,0)

lifeturtle = turtle.Turtle() # turtle for drawing life
lifeturtle.up()
lifeturtle.hideturtle()
lifeturtle.speed(0)
lifeturtle.color('black')

n = 50 # nxn grid
def draw_line(x1,y1,x2,y2): # this function draw a line between x1,y1 and x2,y2
    turtle.up()
    turtle.goto(x1,y1)
    turtle.down()
    turtle.goto(x2,y2)
    
def draw_grid(): # this function draws nxn grid
    turtle.pencolor('gray')
    turtle.pensize(3)
    x = -400
    for i in range(n+1):
        draw_line(x,-400,x,400)
        x += 800/n
    y = -400
    for i in range(n+1):
        draw_line(-400,y,400,y)
        y += 800/n

life = list() # create an empty list
def init_lives():
    for i in range(n):
        liferow = [] # a row of lives
        for j in range(n):
            if random.randint(0,7) == 0: # 1/7 probability of life
                liferow.append(1) # 1 means life
            else:
                liferow.append(0) # 0 means no life
        life.append(liferow) # add a row to the life list -> life is a list of list

def draw_square(x,y,size): # draws a filled square 
    lifeturtle.up()
    lifeturtle.goto(x,y)
    lifeturtle.down()
    lifeturtle.seth(0)
    lifeturtle.begin_fill()
    for i in range(4):
        lifeturtle.fd(size)
        lifeturtle.left(90)
    lifeturtle.end_fill()

def draw_life(x,y): # draws life in (x,y)
    lx = 800/n*x - 400 # converts x,y to screen coordinate 
    ly = 800/n*y - 400
    draw_square(lx+1,ly+1,800/n-2)

def draw_all_life(): # draws all life
    global life
    for i in range(n):
        for j in range(n):
            if life[i][j] == 1: draw_life(i,j) # draw live cells

draw_grid()
init_lives()
draw_all_life()
screen.update()

It should draw a shape like the following image:

Step 4: Updating Life Forever

The next step is to update the life based on the Conway’s Rule:

  1. If a cell with fewer than two or more than three live neighbors dies because of underpopulation or overpopulation.
  2. If a live cell has two or three live neighbors, the cell survives to the next generation.
  3. If a dead cell has exactly three live neighbors, it becomes alive.

We will create a function update_life() that will update the cells based on these rules. Then we will call this function again with the Turtle’s timer event. The following is the complete code for animating the Conway’s Game of Life:

import turtle
import random
import copy

screen=turtle.Screen()
turtle.setup(1000,1000)
turtle.title("Conway's Game of Life - PythonTurtle.Academy")
turtle.hideturtle()
turtle.speed(0)
turtle.tracer(0,0)

lifeturtle = turtle.Turtle() # turtle for drawing life
lifeturtle.up()
lifeturtle.hideturtle()
lifeturtle.speed(0)
lifeturtle.color('black')

n = 50 # nxn grid
def draw_line(x1,y1,x2,y2): # this function draw a line between x1,y1 and x2,y2
    turtle.up()
    turtle.goto(x1,y1)
    turtle.down()
    turtle.goto(x2,y2)
    
def draw_grid(): # this function draws nxn grid
    turtle.pencolor('gray')
    turtle.pensize(3)
    x = -400
    for i in range(n+1):
        draw_line(x,-400,x,400)
        x += 800/n
    y = -400
    for i in range(n+1):
        draw_line(-400,y,400,y)
        y += 800/n

life = list() # create an empty list
def init_lives():
    for i in range(n):
        liferow = [] # a row of lives
        for j in range(n):
            if random.randint(0,7) == 0: # 1/7 probability of life
                liferow.append(1) # 1 means life
            else:
                liferow.append(0) # 0 means no life
        life.append(liferow) # add a row to the life list -> life is a list of list

def draw_square(x,y,size): # draws a filled square 
    lifeturtle.up()
    lifeturtle.goto(x,y)
    lifeturtle.down()
    lifeturtle.seth(0)
    lifeturtle.begin_fill()
    for i in range(4):
        lifeturtle.fd(size)
        lifeturtle.left(90)
    lifeturtle.end_fill()

def draw_life(x,y): # draws life in (x,y)
    lx = 800/n*x - 400 # converts x,y to screen coordinate 
    ly = 800/n*y - 400
    draw_square(lx+1,ly+1,800/n-2)

def draw_all_life(): # draws all life
    global life
    for i in range(n):
        for j in range(n):
            if life[i][j] == 1: draw_life(i,j) # draw live cells

def num_neighbors(x,y): # computes the number of life neighbours for cell[x,y]
    sum = 0
    for i in range(max(x-1,0),min(x+1,n-1)+1):
        for j in range(max(y-1,0),min(y+1,n-1)+1):
            sum += life[i][j]
    return sum - life[x][y]
        
def update_life(): # update life for each cycle
    global life 
    newlife = copy.deepcopy(life) # make a copy of life
    for i in range(n):
        for j in range(n):
            k = num_neighbors(i,j)
            if k < 2 or k > 3:
                newlife[i][j] = 0
            elif k == 3:
                newlife[i][j] = 1
    life = copy.deepcopy(newlife) # copy back to life
    lifeturtle.clear() # clears life in previous cycle
    draw_all_life()
    screen.update() 
    screen.ontimer(update_life,200) # update life every 0.2 second

draw_grid()
init_lives()
update_life()

Related Projects:

Spirograph with Python Turtle

Continuing from Hypotrochoid project, create program that allows users to draw many Hypotrochoid on one canvas to generate a beautiful spirograph. Ask users to enter the following parameters: the ratio of big circle and small circle, the ratio of big circle and distance to trancing point, and the color. When user enters ‘rainbow’ as color, use colorsys library to use all hues gradually when drawing the curve.

Spirograph Creator Animation
Spirograph Generated with Python Turtle
Spirograph Generated with Python Turtle
Spirograph Generated with Python Turtle

Connect Four Game with Monte Carlo Tree and Python Turtle

Monte Carlo Tree is a method based on random numbers that is very effective in playing two player games. You don’t have to teach anything to the program, it will figure out the good moves based on random simulations.

Use Monte Carlo Tree Search Algorithm with Python Turtle to make a smart connect 4 player.

Connect Four with Monte Carlo Tree Algorithm Implemented with Python Turtle
Connect Four with Monte Carlo Tree Algorithm Implemented with Python Turtle