Python Word Find Program

Ezra and I took 30 minutes this evening and wrote a word find puzzle solver in Python.  This uses a little bit of pre-processing, sets, dictionaries, tuples, and other (less efficient) techniques to fairly quickly find the answers.

board = '''
m a i n v f
a n a f d d
s m i t h a
i r o n r v
e m o z a i
a e e t a d
'''
words = '''
ezra
david
sam
smith
iron
fire
'''
# use this to get a dictionary involved.
#words = open('dictionary.txt', 'rt').read()
BOARD = {}
x = 0
y = 0
for line in board.strip().split('\n'):
y += 1
x = 0
for char in line:
char = char.lower()
if char in 'abcdefghijklmnopqrstuvwxyz':
x += 1
BOARD[x,y] = char
WORDS = set()
for line in words.strip().split('\n'):
word = line.strip().lower()
if len(word) >= 3:
WORDS.add(word)
DIREC = (
(0,1),
(1,1),
(1,0),
(1,1),
(0,1),
(1,1),
(1,0),
(1,1),
)
PREFX = set()
FOUND = set()
for word in WORDS:
prefix = ''
for c in word[:1]:
prefix += c
PREFX.add(prefix)
# For each position on the board
for x,y in BOARD:
# For each direction of 8
for xx,yy in DIREC:
x1 = x #cur pos
y1 = y #cur pos
word = '' #cur word
while True:
# Check if off board
if (x1,y1) not in BOARD:
break
# Get character at current pos
word += BOARD[x1,y1]
# If it is a word, add it
if word in WORDS:
FOUND.add(word)
# If this is not a prefix, then bail out
if word not in PREFX:
break
# Increment current position based on direction
x1 += xx
y1 += yy
print(FOUND)

view raw
wordfind.py
hosted with ❤ by GitHub

VisPy Sinewave Demo

VisPy is quite an interesting tool.  They say it is for “scientific visualization”.  Here is an example of that.  I took a demo from their github page and added a little code to generate a sinewave.  The cool thing is that the graph, scaling, panning, zooming, and redrawing all come out of the box.

I previously wrote about installing VisPy.  Thanks to the great efforts of some unnamed people, Python on Windows is really working nicely now.

Here is a screenshot:

vis

Here is the code:

# -*- coding: utf-8 -*-
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
"""
Demonstration of InfiniteLine visual.
"""
import sys
import numpy as np
from vispy import app, scene
# vertex positions of data to draw
N = 200
pos = np.zeros((N, 2), dtype=np.float32)
x_lim = [50., 1750.]
y_lim = [2., 2.]
pos[:, 0] = np.linspace(x_lim[0], x_lim[1], N)
pos[:, 1] = np.random.normal(size=N)
pos1 = np.zeros((20000,2), dtype=np.float32)
color1 = np.ones((20000,4), dtype=np.float32)
pos1[0,0] = 0.0
pos1[0,1] = 15.0
pos1[1,0] = 100.0
pos1[1,1] = 15.0
import math
for x in range(20000):
pos1[x,0] = x*10
pos1[x,1] = math.sin(x/20.) * 40.
# color array
color = np.ones((N, 4), dtype=np.float32)
color[:, 0] = np.linspace(0, 1, N)
color[:, 1] = color[::1, 0]
canvas = scene.SceneCanvas(keys='interactive', show=True)
grid = canvas.central_widget.add_grid(spacing=0)
viewbox = grid.add_view(row=0, col=1, camera='panzoom')
# add some axes
x_axis = scene.AxisWidget(orientation='bottom')
x_axis.stretch = (1, 0.1)
grid.add_widget(x_axis, row=1, col=1)
x_axis.link_view(viewbox)
y_axis = scene.AxisWidget(orientation='left')
y_axis.stretch = (0.1, 1)
grid.add_widget(y_axis, row=0, col=0)
y_axis.link_view(viewbox)
# add a line plot inside the viewbox
#line = scene.Line(pos, color, parent=viewbox.scene)
line1 = scene.Line(pos1, color1, parent=viewbox.scene)
# add vertical lines
vert_line1 = scene.InfiniteLine(100, [1.0, 0.0, 0.0, 1.0],
parent=viewbox.scene)
vert_line2 = scene.InfiniteLine(549.2, [0.0, 1.0, 0.0, 1.0], vertical=True,
parent=viewbox.scene)
# add horizontal lines
hor_line1 = scene.InfiniteLine(0.3, [1.0, 0.0, 1.0, 1.0], vertical=False,
parent=viewbox.scene)
hor_line2 = scene.InfiniteLine(5.1, [1.0, 1.0, 0.0, 1.0], vertical=False,
parent=viewbox.scene)
# auto-scale to see the whole line.
viewbox.camera.set_range((0,1000), (100,100))
if __name__ == '__main__' and sys.flags.interactive == 0:
app.run()

view raw
vis.py
hosted with ❤ by GitHub

Installing VisPy on Windows 10

VisPy is a Python library for interactive scientific visualization that is designed to be fast, scalable, and easy to use.

Here is how I installed it:

First I installed the latest Python 3.6 on Windows 10 by following the directions on http://www.python.org.  Once this was installed, I opened up Windows PowerShell and ran this command:

py -m pip upgrade vispy PyQt5 --user

I found some sample code here, and using NotePad++, copied and pasted it, saving it to Desktop\Code\v1.py

https://github.com/vispy/vispy/blob/master/examples/basics/gloo/animate_shape.py

In PowerShell, I changed to the directory that I saved the python code to and ran it:

cd Desktop\Code
py .\v1.py

Here is the output:

zzzz

It’s a pretty smooth and clean looking UI.  It seems extremely powerful, but I’ll need to dig in and see what makes it tick…

2D Sine Wave Example Using PyOpenGL

Here is an example of a moving 2D sine wave using Python 3, PyGame, and PyOpenGL.  See a https://blog.gahooa.com/2018/02/11/pygame-and-opengl-on-windows-10/  for how to install them.

sine

This sample program is designed to have a 100×60 unit working area with a 10 unit buffer around the edges.  You can see the axis in the lower-left (0,0) where Y+ is up, and X+ is to the right.

The structure of the program was created to make it super easy to work on the “guts” of the graphics without getting it confused with the “bookkeeping” end of OpenGL or PyGame.

Note: the glOrtho() command is how 2D “parallel perspective” is setup.  It defines the left, right, bottom, top, near plane, and far plane.  Because it is parallel, there is not the notion of a “camera” per-se, but rather section of the plane that should be viewed.  Documented here:

https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml

Here is the code!

#!/usr/bin/env python
###############################################################################
# Action Happens Here 50 times per second
def tick(i):
#glRotatef(1, 0, 0, 1)
#glTranslatef(0, 0, 1)
# Draw Axis
axis(i)
# Draw sinewave
for x in range(200):
x = x/2.0
y = math.sin(math.radians(x+i) * 10) * 30 + 30
cquad((x,y,0), 1, (y/60.0,0,x/100.0)) #(center, diameter, color)
###############################################################################
# The rest of this is the bones that make it work
import time
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.arrays import vbo
import math
FPS_TARGET = 50
def axis(i):
glBegin(GL_LINES)
#x = red
#y = green
#z = blue
glColor3f(1, 0, 0)
glVertex3fv((0, 0, 0))
glVertex3fv((1, 0, 0))
glColor3f(0, 1, 0)
glVertex3fv((0, 0, 0))
glVertex3fv((0, 1, 0))
glColor3f(0, 0, 1)
glVertex3fv((0, 0, 0))
glVertex3fv((0, 0, 1))
glEnd()
def quad(points, color):
glBegin(GL_QUADS)
glColor3f(*color)
for p in points:
glVertex3fv(p)
glEnd()
def cquad(point, size, color):
glBegin(GL_QUADS)
glColor3f(*color)
x,y,z = point
s = size/2.0
glVertex3fv((xs,ys,z))
glVertex3fv((x+s,ys,z))
glVertex3fv((x+s,y+s,z))
glVertex3fv((xs,y+s,z))
glEnd()
def main():
#initialize pygame and setup an opengl display
pygame.init()
pygame.display.set_mode((1200,800), OPENGL|DOUBLEBUF)
glEnable(GL_DEPTH_TEST) #use our zbuffer
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#setup the camera
glMatrixMode(GL_PROJECTION)
#gluPerspective(45.0,1000/1000,0.1,1000.0) #setup lens
#glOrtho(-10,10,-10,10,1,20)
glOrtho(10,110,10,70,1,1)
#glTranslatef(0, 0, -100) #move back
#glRotatef(-20, 1, 0, 0) #orbit higher
nt = int(time.time() * 1000)
for i in range(2**63):
nt += 1000//FPS_TARGET
#check for quit'n events
event = pygame.event.poll()
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
break
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
tick(i)
pygame.display.flip()
ct = int(time.time() * 1000)
pygame.time.wait(max(1,nt ct))
if i % FPS_TARGET == 0:
print(ntct)
if __name__ == '__main__': main()

view raw
sinewave.py
hosted with ❤ by GitHub

PyGame and OpenGL on Windows 10

First I went to http://www.python.org and downloaded the latest version of Python for windows.  I made sure to select the option to add it to the system path.

Then I opened windows PowerShell (just a nicer term)

py -m pip install pygame --user
py -m pip install numpy --user
py -m pip install pyopengl --user

(I also installed NoteTab++, a nice text editor)

From there, I went to github and copied one of the examples from https://github.com/pygame/pygame/blob/master/examples/glcube.py and saved it on my desktop as myglcube.py.

In PowerShell, you just type:

cd Desktop
py -m myglcube

Here is my example:

zzz

(here is the code)

#!/usr/bin/env python
"""Draw a cube on the screen. every frame we orbit
the camera around by a small amount and it appears
the object is spinning. note i've setup some simple
data structures here to represent a multicolored cube,
we then go through a semi-unopimized loop to draw
the cube points onto the screen. opengl does all the
hard work for us. :]
"""
import time
import pygame
from pygame.locals import *
try:
from OpenGL.GL import *
from OpenGL.GLU import *
except ImportError:
print ('The GLCUBE example requires PyOpenGL')
raise SystemExit
#some simple data for a colored cube
#here we have the 3D point position and color
#for each corner. then we have a list of indices
#that describe each face, and a list of indieces
#that describes each edge
CUBE_POINTS = (
(0.5, 0.5, 0.5), (0.5, 0.5, 0.5),
(0.5, 0.5, 0.5), (0.5, 0.5, 0.5),
(0.5, 0.5, 0.5), (0.5, 0.5, 0.5),
(0.5, 0.5, 0.5), (0.5, 0.5, 0.5)
)
#colors are 0-1 floating values
CUBE_COLORS = (
(1, 0, 0), (1, 1, 0), (0, 1, 0), (0, 0, 0),
(1, 0, 1), (1, 1, 1), (0, 0, 1), (0, 1, 1)
)
CUBE_QUAD_VERTS = (
(0, 1, 2, 3), (3, 2, 7, 6), (6, 7, 5, 4),
(4, 5, 1, 0), (1, 5, 7, 2), (4, 0, 3, 6)
)
CUBE_EDGES = (
(0,1), (0,3), (0,4), (2,1), (2,3), (2,7),
(6,3), (6,4), (6,7), (5,1), (5,4), (5,7),
)
def drawcube():
"draw the cube"
allpoints = list(zip(CUBE_POINTS, CUBE_COLORS))
glBegin(GL_QUADS)
for face in CUBE_QUAD_VERTS:
for vert in face:
pos, color = allpoints[vert]
glColor3fv(color)
glVertex3fv(pos)
glEnd()
glColor3f(1.0, 1.0, 1.0)
glBegin(GL_LINES)
"""
for line in CUBE_EDGES:
for vert in line:
pos, color = allpoints[vert]
glVertex3fv(pos)
"""
for x in range(50,50):
glColor3f(x*.03%1.0, x*.04%1.0, x*.05%1.0)
glVertex3fv((x, 0, 100))
glVertex3fv((x, 0, 100))
glVertex3fv((100, 0, x))
glVertex3fv((100, 0, x))
glEnd()
def main():
"run the demo"
#initialize pygame and setup an opengl display
pygame.init()
pygame.display.set_mode((1024,768), OPENGL|DOUBLEBUF)
glEnable(GL_DEPTH_TEST) #use our zbuffer
#setup the camera
glMatrixMode(GL_PROJECTION)
gluPerspective(45.0,1024/768.0,0.1,100.0) #setup lens
glTranslatef(0.0, 0.0, 20.0) #move back
glRotatef(60, 1, 0, 0) #orbit higher
nt = int(time.time() * 1000)
for i in range(2**63):
nt += 20
glTranslatef(0.0, 0.0, .1)
#check for quit'n events
event = pygame.event.poll()
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
break
#clear screen and move camera
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
#orbit camera around by 1 degree
glRotatef(1, 0, 1, 0)
drawcube()
pygame.display.flip()
ct = int(time.time() * 1000)
pygame.time.wait(max(1,nt ct))
if i % 50 == 0:
print(ntct)
if __name__ == '__main__': main()

view raw
myglcube.py
hosted with ❤ by GitHub

 

 

Python 3 bytes indexing returns integers!

While converting a bunch of werkzeug code to Python 3.1, I ran into an issue with one of the bytes objects that was previously a string.

The line of code in question was originally this:

if value and value[0] == value[-1] == b'"':
   ...

If value is something, and the first and last characters are a quote character, then…

However, as it turns out, the bytes object is actually a list of integers in the range of 0-255.

So when you use an indexing operation on a byte, you actually get an integer back. For example:

>>> x = b'Hello World'
>>> x[0]
72

>>> x = 'Hello World'
>>> x[0]
'H'

Big difference, eh?

Python 3.1 and mod_wsgi performance notes

We’re researching the use of Python and mod_wsgi running under apache for developing some extensive web applications.  Here are some notes on a performance test that we recently ran.
==================================================================
Server:

x86_64
Python 3.1.1
mod_wsgi 3.0c5
apache 2.2
RHEL 5.3
quad core xenon
8 GB ram

Development system – not in production use.

==================================================================
Application:

1 import time
2
3 def application(environ, start_response):
4     status = ‘200 OK’
5
6     output = “hello world!”
7
8     #time.sleep(1)
9
10     response_headers = [
11         (‘Content-type’, ‘text/plain’),
12         (‘Content-Length’, str(len(output))),
13         ]
14
15     start_response(status, response_headers)
16
17     return [output]

==================================================================
Apache Configuration:

WSGISocketPrefix run/wsgi
<VirtualHost *>
ServerName shankproject.jason.star.ionzoft.net
DocumentRoot /home/jason/Code/ShankProject/Web
WSGIScriptAlias /Admin /home/jason/Code/ShankProject/WSGI/
Admin.wsgi
WSGIDaemonProcess shankproject.jason.star.ionzoft.net threads=15
WSGIProcessGroup shankproject.jason.star.ionzoft.net
</VirtualHost>

==================================================================
Tests:

—————————————————–
# Baseline with one process and 15 threads
# 15 threads total

threads=15
no process definition

WITHOUT time.sleep(1)
concurrency = 1  >> 1800 / second
concurrency = 100 >> 3900 / second

WITH time.sleep(1)
concurrency = 1  >> 1 / second
concurrency = 100  >> 14 / second

—————————————————–
# Get a marginal improvement by doubling the threads to 30
# 30 threads total

threads=30
no process definition

WITHOUT time.sleep(1)
concurrency = 1  >> 1680 / second
concurrency = 100 >> 3500 / second

WITH time.sleep(1)
concurrency = 1  >> 1 / second
concurrency = 100  >> 30 / second

—————————————————–
# Take processes from 1 to 3
# 90 threads total

threads=30
processes=3

WITHOUT time.sleep(1)
concurrency = 1  >> 1770 / second
concurrency = 100 >> 3500 / second

WITH time.sleep(1)
concurrency = 1  >> 1 / second
concurrency = 100  >> 88 / second

—————————————————–
# Take processes from 3 to 6
# Take threads from 30 to 15
# 90 threads total

threads=30
processes=3

WITHOUT time.sleep(1)
concurrency = 1  >> 1550 / second
concurrency = 100 >> 3300 / second

WITH time.sleep(1)
concurrency = 1  >> 1 / second
concurrency = 100  >> 88 / second

==================================================================
Conclusion:

mod_wsgi performance is outstanding.  Even running slower requests, it
can still handle significant concurrency in daemon mode without any
apparent issues.

Questions:
Is there any information on the balance between more processes less
threads and more threads less processes?

Thanks!