Cobra com fome de imagem - Buraco # 3

25

Buraco # 1

Joe, a cobra, está com fome.

Ele come fotos, um pixel de cada vez.

Ele realmente gosta de pixels brilhantes.

O desafio

Programe Joe para comer os pixels mais brilhantes que conseguir encontrar, pois ele só pode se mover para cima, baixo, esquerda ou direita.

Especificações

  • Joe deve começar no pixel superior esquerdo da imagem.
  • Joe só pode se mover horizontalmente ou verticalmente por 1 cada movimento
  • Joe tem apenas tempo suficiente para mover 1/3 da quantidade de pixels na imagem (1/3 do número de movimentos que pixels). Se o número de pixels não for múltiplo de 3, arredonde para o número inteiro mais próximo.
  • Joe pode cruzar seu caminho, embora isso conte como 0 brilho
  • O brilho é baseado na soma de r, g e b, de modo que rgb (0,0,0) possui um brilho de 0 enquanto rgb (255,255,255) possui brilho máximo.

Entrada

Você pode inserir a imagem como quiser.

Saída

  • uma imagem mostrando o resultado final da sua foto (com pixels sendo comidos em preto).
  • A quantidade de brilho consumida (especifique qual intervalo em sua resposta)

Pontuação

Seu programa será classificado em:

  • O brilho médio dos pixels que Joe come / O brilho médio dos pixels na imagem *

* você pode codificar isso no seu programa

Sua pontuação total será a média das pontuações das seguintes imagens:

Imagens de teste:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

http://upload.wikimedia.org/wikipedia/en/thumb/f/f4/The_Scream.jpg/800px-The_Scream.jpg

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Stretch Maniac
fonte
3
Fun Markdown fato - Você pode transformar imagens em links para seus originais: [![image description](SE URL for downsized image)](URL for original image).
Hobbies de Calvin
1
Pode ser uma ideia pedir às pessoas para incluir um exemplo de imagem "comida" em suas respostas.
21314 Nathaniel
1 imagem está quebrada: upload.wikimedia.org/wikipedia/en/thumb/f/f4/The_Scream.jpg/…
Ferrybig 12/02/16

Respostas:

16

C ++, Pontuação: 1.42042 1.46766

Esta é essencialmente uma versão um pouco mais sofisticada das duas soluções existentes: Dos quatro movimentos possíveis, ele seleciona aquele que maximiza o brilho. No entanto, em vez de apenas observar o brilho do pixel de destino, ele analisa a soma ponderada de brilho de pixel na vizinhança do pixel de destino, onde os pixels mais próximos do alvo têm um peso maior.

EDIT: O uso do brilho não linear no cálculo da vizinhança melhora um pouco a pontuação.

Compile com g++ joe.cpp -ojoe -std=c++11 -O3 -lcairo. Requer cairo.

Corra com joe <image-file> [<radius>]. <image-file>é a imagem PNG de entrada. <radius>(argumento opcional) é o raio da vizinhança resumida, em pixels (menor é mais rápido, maior é (aproximadamente) melhor).) Emite a pontuação e uma imagem chamada out.<image-file>.

#include <cairo/cairo.h>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>

using namespace std;

int main(int argc, const char* argv[]) {
    auto* img = cairo_image_surface_create_from_png(argv[1]);
    int width = cairo_image_surface_get_width(img),
        height = cairo_image_surface_get_height(img),
        stride = cairo_image_surface_get_stride(img);
    unsigned char* data = cairo_image_surface_get_data(img);

    double* brightness = new double[width * height];
    double total_brightness = 0;
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            const unsigned char* p = data + stride * y + 4 * x;
            total_brightness += brightness[y * width + x] = p[0] + p[1] + p[2];
        }
    }

    const int r = argc > 2 ? stoi(argv[2]) : 64, R = 2 * r + 1;
    double* weight = new double[R * R];
    for (int y = -r; y <= r; ++y) {
        for (int x = -r; x <= r; ++x)
            weight[R * (y + r) + (x + r)] = 1.0 / (x*x + y*y + 1);
    }

    auto neighborhood = [&] (int x, int y) {
        double b = 0;
        int x1 = max(x - r, 0), x2 = min(x + r, width - 1);
        int y1 = max(y - r, 0), y2 = min(y + r, height - 1);
        for (int v = y1; v <= y2; ++v) {
            const double *B = brightness + width * v + x1;
            const double *W = weight + R * (v - (y - r)) + (x1 - (x - r));
            for (int u = x1; u <= x2; ++u, ++B, ++W)
                b += (*W) * (*B) * (*B);
        }
        return b;
    };

    int n = (2 * width * height + 3) / 6;
    int x = 0, y = 0;
    double path_brightness = 0;
    int O[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    for (int i = 0; i < n; ++i) {
        if (i % 1000 == 0) cerr << (200 * i + n) / (2 * n) << "%\r";

        path_brightness += brightness[width * y + x]; brightness[width * y + x] = 0;
        unsigned char* p = data + stride * y + 4 * x;
        p[0] = p[1] = 16 * i % 255; p[2] = 0;

        auto O_end = partition(begin(O), end(O), [&] (const int* o) {
            return x + o[0] >= 0 && x + o[0] < width &&
                   y + o[1] >= 0 && y + o[1] < height;
        });
        const int* o_max; double o_max_neighborhood = -1;
        for (auto o = O; o != O_end; ++o) {
            double o_neighborhood = neighborhood(x + (*o)[0], y + (*o)[1]);
            if (o_neighborhood > o_max_neighborhood)
                o_max = *o, o_max_neighborhood = o_neighborhood;
        }
        x += o_max[0]; y += o_max[1];
    }

    cout << (path_brightness * width * height) / (n * total_brightness) << endl;

    cairo_surface_write_to_png(img, (string("out.") + argv[1]).c_str());

    delete []brightness;
    delete []weight;
    cairo_surface_destroy(img);
}

Resultados

Bridge    1.39945
Balls     1.77714
Scream    1.38349
Fractal   1.31727
Vortex    1.66493
Tornado   1.26366
-----------------
Average   1.46766

Ponte Bolas Grito Fractal Vórtice Tornado

Mais colírio para os olhos

Animação de vórtice Animação Tornado

Ell
fonte
Eu apenas tentei o seu programa em algumas de minhas próprias imagens de amostra, e uma tem muito preto apenas em torno do ponto de partida, e aí o programa trava devido ao lambda do bairro retornando NaN.
PlasmaHH
@PlasmaHH Mind compartilhando a imagem ofensiva?
Ell
Eu estava alimentando imagens de férias ... 400x400 em preto puro faz o "truque" também.
PlasmaHH
@PlasmaHH Bem, uma imagem puramente preta tem uma pontuação indefinida, é zero acima de zero, o que seria um NaN. Ele não deve afetar o cálculo bairro, porém, ou travar o programa (embora isto pode depender do ambiente de ponto flutuante.)
Ell
Dê uma olhada no ponteiro o_max, if (o_neighborhood > o_max_neighborhood) o_max = *o, o_max_neighborhood = o_neighborhood;apenas este código o define. no entanto, devido ao nan envolvido, a comparação é sempre falsa, portanto o_max nunca é definido e usado não inicializado.
PlasmaHH #
7

Python 3, pontuação = 1,57

Primeiro, nossa cobra viaja pela imagem, criando linhas verticais com a mesma distância uma da outra.

uma

Podemos estender essa cobra colocando dois pontos próximos um do outro em uma linha vertical e criando um loop cujos pontos finais são eles.

|      |
|  =>  +----+
|      +----+
|      |

Organizamos os pontos em pares e, para cada par, armazenamos o tamanho e o valor médio de brilho do loop, que fornece o maior brilho médio.

A cada passo, escolhemos o par com o valor mais alto, estendendo seu loop para obter o brilho médio máximo na extensão e calculando o novo tamanho de loop e valor de brilho ideais para o par.

Armazenamos os trigêmeos (value, size, point_pair) em uma estrutura de heap classificada por valor, para que possamos remover o elemento maior (em O (1)) e adicionar o novo elemento modificado (em O (log n)) com eficiência.

Paramos quando atingimos o limite de contagem de pixels e essa cobra será a cobra final.

A distância entre as linhas verticais tem muito pouco efeito nos resultados, portanto, uma constante de 40 pixels foi escolhida.

Resultados

swirl    1.33084397946
chaos    1.76585674741
fractal  1.49085737611
bridge   1.42603926741
balls    1.92235115238
scream   1.48603818637
----------------------
average  1.57033111819

uma uma uma uma uma uma

Nota: a imagem original "The Scream" não estava disponível, então usei outra imagem "The Scream" com resolução semelhante.

Gif mostrando o processo de extensão da cobra na imagem "redemoinho":

uma

O código pega um (ou mais espaços) nome do arquivo stdin e grava as imagens de cobra resultantes em arquivos png e imprime as pontuações no stdout.

from PIL import Image
import numpy as np
import heapq as hq

def upd_sp(p,st):
    vs,c=0,0
    mv,mp=-1,0
    for i in range(st,gap):
        if p[1]+i<h:
            vs+=v[p[0],p[1]+i]+v[p[0]+1,p[1]+i]
            c+=2
            if vs/c>mv:
                mv=vs/c
                mp=i
    return (-mv,mp)

mrl=[]
bf=input().split()

for bfe in bf:
    mr,mg=0,0    
    for gap in range(40,90,1500):

        im=Image.open(bfe)
        im_d=np.asarray(im).astype(int)

        v=im_d[:,:,0]+im_d[:,:,1]+im_d[:,:,2]

        w,h=v.shape

        fp=[]
        sp=[]
        x,y=0,0
        d=1

        go=True
        while go:
            if 0<=x+2*d<w:
                fp+=[(x,y)]
                fp+=[(x+d,y)]
                sp+=[(x-(d<0),y)]
                x+=2*d
                continue
            if y+gap<h:
                for k in range(gap):
                    fp+=[(x,y+k)]
                y+=gap
                d=-d
                continue
            go=False

        sh=[]
        px=im.load()

        pl=[]

        for p in fp:
            pl+=[v[p[0],p[1]]]
            px[p[1],p[0]]=(0,127,0)   

        for p in sp:
            mv,mp=upd_sp(p,1)
            if mv<=0:
                hq.heappush(sh,(mv,1,mp+1,p))

        empty=False
        pleft=h*w//3
        pleft-=len(fp)
        while pleft>gap*2 and not empty:

            if len(sh)>0:
                es,eb,ee,p=hq.heappop(sh)
            else:
                empty=True
            pleft-=(ee-eb)*2

            mv,mp=upd_sp(p,ee)
            if mv<=0:
                hq.heappush(sh,(mv,ee,mp+1,p))    

            for o in range(eb,ee):
                pl+=[v[p[0],p[1]+o]]
                pl+=[v[p[0]+1,p[1]+o]]
                px[p[1]+o,p[0]]=(0,127,0)   
                px[p[1]+o,p[0]+1]=(0,127,0)

        pl+=[0]*pleft

        sb=sum(pl)/len(pl)
        ob=np.sum(v)/(h*w)

        im.save(bfe[:-4]+'snaked.png')

        if sb/ob>mr:
            mr=sb/ob
            mg=gap

    print(bfe,mr)
    mrl+=[mr]

print(sum(mrl)/len(mrl))
randomra
fonte
5

Python 2 (pontuação: 0.0797116)

Apenas um algoritmo ganancioso muito simples e ingênuo para fazer a bola rolar.

#!/usr/bin/python

from PIL import Image

OFFSETS = [(-1, 0), (0, -1), (1, 0), (0, 1)]
def test_img(filename):
    img = Image.open(filename)

    joe, eaten = (0, 0), []
    img_w, img_h = img.size
    all_pixels = [
        sum(img.getpixel((x, y)))
        for x in xrange(img_w)
        for y in xrange(img_h)
    ]
    total_brightness = float(sum(all_pixels)) / len(all_pixels)

    for _ in xrange(0, (img_w*img_h)/3):
        max_offset, max_brightness = (0, 0), 0
        for o in OFFSETS:
            try:
                brightness = sum(img.getpixel((joe[0] + o[0], joe[1] + o[1])))
            except IndexError:
                brightness = -1
            if brightness >= max_brightness:
                max_offset = o
                max_brightness = brightness

        joe = (joe[0] + max_offset[0], joe[1] + max_offset[1])
        eaten.append(max_brightness)
        img.putpixel(joe, (0, 0, 0))

    eaten_brightness = float(sum(eaten)) / len(eaten)
    print('%d of %d (score %f)' % (eaten_brightness, total_brightness, eaten_brightness / total_brightness))
    img.show()

test_img('img0.jpg')
test_img('img1.png')
test_img('img2.jpg')
test_img('img3.jpg')
test_img('img4.jpg')

Saída:

llama@llama:~/Code/python/ppcg40069hungrysnake$ ./hungrysnake.py 
15 of 260 (score 0.060699)
9 of 132 (score 0.074200)
16 of 300 (score 0.055557)
4 of 369 (score 0.010836)
79 of 400 (score 0.197266)
Maçaneta da porta
fonte
1
Eu acho que sua pontuação está errada. É a média de brilho de Joe comido todo o brilho médio para toda a imagem ... A aleatória Joe deve obter uma pontuação de cerca de 1.
estiramento Maniac
@StretchManiac Hmm, não vejo nada de errado. sum of brightnesses of eaten pixels / amount of eaten pixelsé a fórmula certa, correto? Talvez seja apenas um algoritmo realmente terrível;)
Maçaneta da porta
@Doorknob it isThe average brightness of pixels Joe eats / The average brightness of the pixels in the picture*
hmatt1 /
Para o swirly laranja e preto (não azul), obtive um brilho médio de 68.0846 ... O que não parece coincidir com o seu. Talvez sum (getPixel (...)) não retorne o que você deseja? (Eu sou um novato em python). BTW, existem 6 imagens, mas você só tem 5 saídas. Você também pode rotular as imagens de alguma forma?
Stretch Maniac
@StretchManiac Como você está calculando seu brilho? O meu apenas soma os valores R, G e B. Desculpe, eu perdi o swirly que vem em penúltimo lugar (o que você mencionou no seu comentário, eu acho). Vou acrescentar isso de manhã (tenho que dormir agora).
Maçaneta
5

Java (pontuação: 0.6949)

Um algoritmo simples que obtém o pixel mais brilhante dos quatro pixels ao redor do pixel atual. No caso de empate, o pixel comido é aleatório, levando a pontuações diferentes e imagens resultantes a cada execução. Assim, as pontuações abaixo são as médias de mais de 50 execuções em cada imagem.

Para executá-lo, edite os três argumentos (existentes como constantes de classe) na fonte ou passe-os por linha de comando no formulário java HungryImageSnake <source> <iterations> <printScores>onde <source>está o arquivo de origem da imagem a ser consumida, <iterations>é o número de vezes em que a imagem é consumida (usando a pontuação média e salvando a melhor pontuação em todas as iterações) e <printScores>é verdadeiro imprimir a pontuação de cada iteração ou falso em não.

import javax.imageio.ImageIO;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

public class HungryImageSnake {

    private static final String SOURCE = "tornado.jpg";
    private static final int ITERATIONS = 50;
    private static final boolean PRINT_SCORES = true;

    public static void main(String[] args) {
        try {
            String source = args.length > 0 ? args[0] : SOURCE;
            int iterations = args.length > 1 ? Integer.parseInt(args[1]) : ITERATIONS;
            boolean printScores = args.length > 2 ? Boolean.parseBoolean(args[2]) : PRINT_SCORES;

            System.out.printf("Reading '%s'...%n", source);
            System.out.printf("Performing %d meals...%n", iterations);
            BufferedImage image = ImageIO.read(new File(source));
            double totalScore = 0;
            double bestScore = 0;
            BufferedImage bestImage = null;
            for (int i = 0; i < iterations; i++) {
                HungryImageSnake snake = new HungryImageSnake(image);
                while (snake.isHungry()) {
                    snake.eat();
                }
                double score = snake.getScore();
                if (printScores) {
                    System.out.printf("    %d: score of %.4f%n", i + 1, score);
                }
                totalScore += score;
                if (bestImage == null || score > bestScore) {
                    bestScore = score;
                    bestImage = snake.getImage();
                }
            }
            System.out.printf("Average score: %.4f%n", totalScore / iterations);
            String formattedScore = String.format("%.4f", bestScore);
            String output = source.replaceFirst("^(.*?)(\\.[^.]+)?$", "$1-b" + formattedScore + "$2");
            ImageIO.write(bestImage, source.substring(source.lastIndexOf('.') + 1), new File(output));
            System.out.printf("Wrote best image (score: %s) to '%s'.%n", bestScore, output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private int x;
    private int y;
    private int movesLeft;
    private int maximumMoves;
    private double eatenAverageBrightness;
    private double originalAverageBrightness;
    private BufferedImage image;

    public HungryImageSnake(BufferedImage image) {
        this.image = copyImage(image);
        int size = image.getWidth() * image.getHeight();
        this.maximumMoves = size / 3;
        this.movesLeft = this.maximumMoves;
        int totalBrightness = 0;
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                totalBrightness += getBrightnessAt(x, y);
            }
        }
        this.originalAverageBrightness = totalBrightness / (double) size;
    }

    public BufferedImage getImage() {
        return image;
    }

    public double getEatenAverageBrightness() {
        return eatenAverageBrightness;
    }

    public double getOriginalAverageBrightness() {
        return originalAverageBrightness;
    }

    public double getScore() {
        return eatenAverageBrightness / originalAverageBrightness;
    }

    public boolean isHungry() {
        return movesLeft > 0;
    }

    public void eat() {
        if (!isHungry()) {
            return;
        }
        int[][] options = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
        shuffleArray(options); // prevent snake from getting stuck in corners
        int[] bestOption = null;
        int bestBrightness = 0;
        for (int[] option : options) {
            int optionX = this.x + option[0];
            int optionY = this.y + option[1];
            if (exists(optionX, optionY)) {
                int brightness = getBrightnessAt(optionX, optionY);
                if (bestOption == null || brightness > bestBrightness) {
                    bestOption = new int[]{ optionX, optionY };
                    bestBrightness = brightness;
                }
            }
        }

        image.setRGB(bestOption[0], bestOption[1], 0);
        this.movesLeft--;
        this.x = bestOption[0];
        this.y = bestOption[1];
        this.eatenAverageBrightness += bestBrightness / (double) maximumMoves;
    }

    private boolean exists(int x, int y) {
        return x >= 0 && x < image.getWidth() && y >= 0 && y < image.getHeight();
    }

    private int getBrightnessAt(int x, int y) {
        int rgb = image.getRGB(x, y);
        int r = (rgb >> 16) & 0xFF;
        int g = (rgb >> 8) & 0xFF;
        int b = rgb & 0xFF;
        return r + g + b;
    }

    private static <T> void shuffleArray(T[] array) {
        Random random = new Random();
        for (int i = array.length - 1; i > 0; i--) {
            int index = random.nextInt(i + 1);
            T temp = array[index];
            array[index] = array[i];
            array[i] = temp;
        }
    }

    private static BufferedImage copyImage(BufferedImage source){
        BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
        Graphics g = b.getGraphics();
        g.drawImage(source, 0, 0, null);
        g.dispose();
        return b;
    }
}

Pontuações médias, por imagem, em mais de cinquenta iterações:

Bridge - 0.7739
Spheres - 0.5580
Scream - 0.8197
Fractal - 0.3850
Vortex - 0.9158
Tornado - 0.7172

Melhores pontuações, por imagem, nas mesmas cinquenta iterações:

Bridge - 0.8996
Spheres - 0.8741
Scream - 0.9183
Fractal - 0.5720
Vortex - 1.1520
Tornado - 0.9281

As imagens das execuções com maior pontuação:

Ponte - 0.8996 Esferas - 0.8741 Scream - 0.9183 Fractal - 0.5720 Vortex - 1.1520 Tornado - 0.9281

Como é evidente nas imagens, muito menos de um terço dos pixels são realmente consumidos, pois a cobra ocasionalmente fica presa entre os pixels que já ingeriu, nos quais permanece presa na área morta até que a aleatoriedade de seus movimentos a faça cair. uma parte comestível da imagem.

Também como resultado dos pixels que a cobra comeu novamente, as pontuações são enviesadas para baixo, pois o brilho zero dos pixels mortos é novamente considerado na média. Eu esperaria ver pontuações muito mais altas se o algoritmo de pontuação fosse modificado para dividir apenas pelo número de movimentos que levaram a comer novos pixels, em vez de todos os movimentos (incluindo aqueles em que a cobra come um pixel agora morto que ele havia comido antes )

Obviamente, uma abordagem melhor seria criar algum tipo de heurística de brilho para cada pixel e encontrar o caminho dos width * height / 3pixels com o brilho médio mais alto, mas duvido que essa abordagem seja ideal em tempo de execução, especialmente em imagens maiores, como o número possíveis permutações seria muito grande. Posso tentar alguma forma dessa abordagem posteriormente e publicá-la em uma resposta separada, se for o caso.

FThompson
fonte
Se alguém se incomodar com o tamanho da minha resposta (devido às imagens), avise-me e removerei as imagens em favor de links ou outra alternativa menos exigente. Ou, se alguém quiser os originais em resolução total de qualquer imagem "comida", informe-me também em um comentário.
FThompson
4

Python 2, Pontuação: 1.205

Eu montei uma solução rápida em Python há algum tempo, mas esqueci de publicá-la. Aqui está. Ele encontra os blocos mais ricos da imagem e viaja para cada bloco, comendo todos os melhores blocos.

Resultados

bridge.jpg: 591.97866/515.41501 =                               1.14855 
BallsRender.png: 493.24711/387.80635 =                          1.27189 
Mandel_zoom_04_seehorse_tail.jpg: 792.23990/624.60579 =         1.26838 
Red_Vortex_Apophysis_Fractal_Flame.jpg: 368.26121/323.08463 =   1.13983 
The_Scream.jpg: 687.18565/555.05221 =                           1.23806
swirl.jpg: 762.89469/655.73767 =                                1.16341

AVERAGE                                                         1.205

Exemplo de imagem

Imagem de ponte processada

Código Python 2.7

from pygame.locals import *
import pygame, sys, random

fn = sys.argv[1]

screen = pygame.display.set_mode((1900,1000))
pic = pygame.image.load(fn)
pic.convert()
W,H = pic.get_size()
enough = W*H/3
screen.blit(pic, (0,0))

ORTH = [(-1,0), (1,0), (0,-1), (0,1)]
def orth(p):
    return [(p[0]+dx, p[1]+dy) for dx,dy in ORTH]

def look(p):
    x,y = p
    if 0 <= x < W and 0 <= y < H:
        return sum(pic.get_at(p))
    else:
        return -1

# index picture
locs = [(x,y) for x in range(W) for y in range(H)]
grid = dict( (p,sum(pic.get_at(p))) for p in locs )
rank = sorted( grid.values() )
median = rank[ len(rank)/2 ]
dark = dict( (k,v) for k,v in grid if v < median )
good = dict( (k,v) for k,v in grid if v > median )
pictotal = sum(rank)
picavg = 1.0 * pictotal/(W*H)
print('Indexed')

# compute zone values:
block = 16
xblocks, yblocks = (W-1)/block, (H-1)/block
zones = dict( ((zx,zy),0) for zx in range(xblocks) for zy in range(yblocks) )
for x,y in locs:
    div = (x/block, y/block)
    if div in zones:
        colsum = sum( pic.get_at((x,y)) )
        zones[div] += colsum

# choose best zones:
zonelist = sorted( (v,k) for k,v in zones.items() )
cut = int(xblocks * yblocks * 0.33)
bestzones = dict( (k,v) for v,k in zonelist[-cut:] )

# make segment paths:
segdrop = [(0,1)] * (block-1)
segpass = [(1,0)] * block
segloop = [(0,-1)] * (block-1) + [(1,0)] + [(0,1)] * (block-1)
segeat = ( segloop+[(1,0)] ) * (block/2)
segshort = [(1,0)] * 2 + ( segloop+[(1,0)] ) * (block/2 - 1)

def segtopath(path, seg, xdir):
    for dx,dy in seg:
        x,y = path[-1]
        newloc = (x+dx*xdir, y+dy)
        path.append(newloc)

# design good path:
xdir = 1
path = [(0,0)]
segtopath(path, segdrop, xdir)
shortzone = True
while True:
    x,y = path[-1]
    zone = (x/block, y/block)
    if zone in bestzones:
        if shortzone:
            seg = segshort
        else:
            seg = segeat
    else:
        seg = segpass
    segtopath(path, seg, xdir)
    shortzone = False
    # check end of x block run:
    x,y = path[-1]
    zone = (x/block, y/block)
    if not ( 0 <= x < xblocks*block ):
        del path[-1]
        segtopath(path, segdrop, xdir)
        shortzone = True
        xdir = xdir * -1
    if len(path) > enough:
        break
print('Path Found')

# show path on picture:
loc = path.pop(0)
eaten = 1
joetotal = grid[loc]
i = 0
while eaten <= enough:
    loc = path[i]
    i += 1
    pic.set_at(loc, (0,0,0))
    joetotal += grid[loc]
    eaten += 1
    if i % 1000 == 0:
        screen.blit(pic, (0,0))
        pygame.display.flip()
        for event in pygame.event.get():
            if event.type == QUIT: sys.exit(0)

# save picture and wait:
screen.blit(pic, (0,0))
pygame.display.flip()
pygame.image.save(pic, 'output/'+fn)
joeavg = 1.0 * joetotal/eaten
print '%s: %7.5f/%7.5f = %7.5f' % (fn, joeavg, picavg, joeavg/picavg)
while True:
    for event in pygame.event.get():
        if event.type == QUIT: sys.exit(0)
Cavaleiro Lógico
fonte