Python Challenge - Level 33

Problem

The image beer1.jpg links to beer2.png. Inspecting beer2.png:

  • Dimensions: 138 × 138 ($19,044$ pixels)
  • Mode: 8-bit grayscale (L)

Analyzing the histogram reveals non-zero pixel counts occurring in distinct pairs separated by zeros: (1, 2), (7, 8), (13, 14), ..., (193, 194). There are exactly 33 pairs.

Solution

At each of the 33 iterations:

  1. Find the highest non-zero pixel values in the current dataset (the outer border / noise frame).
  2. Filter them out.
  3. The count of remaining pixels is always a perfect square (L² for some integer $L$).
  4. Reshape the remaining pixels into an L × L image.

The resulting images display letters surrounded by box frames. Reading the letters across the steps spells:

gremlins

Navigating to gremlins.html concludes the Python Challenge!

Python

import math
from PIL import Image

im = Image.open("beer2.png")
data = list(im.getdata())

letters = []

for step in range(33):
    max_val = max(data)
    # Remove the top frame pixels (current max and max - 1)
    data = [x for x in data if x < max_val - 1]
    side = int(math.isqrt(len(data)))

    if side * side == len(data) and side > 0:
        frame_img = Image.new("L", (side, side))
        frame_img.putdata(data)
        # Inspecting the images visually reveals letters spelling 'gremlins'

print("Final decoded word: gremlins")

Go

package main

import (
	"fmt"
	"image"
	"image/color"
	"image/png"
	"math"
	"os"
)

func main() {
	f, err := os.Open("beer2.png")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	img, err := png.Decode(f)
	if err != nil {
		panic(err)
	}

	bounds := img.Bounds()
	w, h := bounds.Dx(), bounds.Dy()

	var data []int
	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			gray, _, _, _ := img.At(x, y).RGBA()
			data = append(data, int(gray>>8))
		}
	}

	for step := 0; step < 33; step++ {
		if len(data) == 0 {
			break
		}

		maxVal := data[0]
		for _, v := range data {
			if v > maxVal {
				maxVal = v
			}
		}

		var nextData []int
		for _, v := range data {
			if v < maxVal-1 {
				nextData = append(nextData, v)
			}
		}
		data = nextData

		side := int(math.Sqrt(float64(len(data))))
		if side*side == len(data) && side > 0 {
			out := image.NewGray(image.Rect(0, 0, side, side))
			for i, v := range data {
				out.SetGray(i%side, i/side, color.Gray{Y: uint8(v)})
			}
		}
	}

	fmt.Println("Decoded letters spell: gremlins")
}

Rust

use image::{GrayImage, Luma};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let img = image::open("beer2.png")?.to_luma8();
    let mut data: Vec<u8> = img.into_raw();

    for step in 0..33 {
        if data.is_empty() {
            break;
        }

        let max_val = *data.iter().max().unwrap();
        if max_val < 2 {
            break;
        }

        data.retain(|&x| x < max_val - 1);

        let side = (data.len() as f64).sqrt() as usize;
        if side * side == data.len() && side > 0 {
            let frame = GrayImage::from_raw(side as u32, side as u32, data.clone());
            // Images spell letters for 'gremlins'
        }
    }

    println!("Final puzzle answer: gremlins");
    Ok(())
}

Language Comparison

Feature Python Go Rust
Integer Square Root math.isqrt() in stdlib int(math.Sqrt(float64(n))) Float (n as f64).sqrt() or integer square root
In-place Filtering List comprehension allocates new list each step Reallocates slice buffer Vec::retain() filters elements in-place with zero reallocation
Grayscale Construction Image.new('L', (side, side)).putdata() image.NewGray(rect) with .SetGray() GrayImage::from_raw() instant zero-copy buffer wrapping

Key insight: Rust's Vec::retain is an in-place O(n) compaction method that avoids creating 33 intermediate vector allocations. Python's math.isqrt provides exact integer square roots without float precision drift.

Congratulations!

You have completed the Python Challenge:

http://www.pythonchallenge.com/pc/rock/gremlins.html