Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm looking for a way to generate the following the series of numbers given the version number on the left. For example, given "2", generate [6, 18]. The series of numbers is from the alignment pattern locations for different versions of QR codes.

 V2  6  18
 V3  6  22
 V4  6  26
 V5  6  30
 V6  6  34
 V7  6  22  38
 V8  6  24  42
 V9  6  26  46
V10  6  28  50
V11  6  30  54
V12  6  32  58
V13  6  34  62
V14  6  26  46  66
V15  6  26  48  70
V16  6  26  50  74
V17  6  30  54  78
V18  6  30  56  82
V19  6  30  58  86
V20  6  34  62  90
V21  6  28  50  72   94
V22  6  26  50  74   98
V23  6  30  54  78  102
V24  6  28  54  80  106
V25  6  32  58  84  110
V26  6  30  58  86  114
V27  6  34  62  90  118
V28  6  26  50  74   98  122
V29  6  30  54  78  102  126
V30  6  26  52  78  104  130
V31  6  30  56  82  108  134
V32  6  34  60  86  112  138
V33  6  30  58  86  114  142
V34  6  34  62  90  118  146
V35  6  30  54  78  102  126  150
V36  6  24  50  76  102  128  154
V37  6  28  54  80  106  132  158
V38  6  32  58  84  110  136  162
V39  6  26  54  82  110  138  166
V40  6  30  58  86  114  142  170

I've come up with the following Python code which generates the correct sequences, but contains an "exceptional" condition for V32, expressed in the if statement.

import math

def pattern(ver):
    w = 21 + ((ver - 1) * 4)       # Width
    h = 6                          # First item
    t = (w - 1) - 6                # Last item
    r = t - h                      # Distance between first and last
    n = math.ceil(r/28)            # Number of items in list - 1

    if (w == 145):
        intervals = 26             # Anomaly
    else:
        intervals = math.ceil(r/n) # Ceiling to nearest multiple of 2
        intervals = intervals + (intervals % 2)

    xs = [t]
    for m in (n-1) * [intervals]: xs.append(xs[-1] - m)
    xs.append(h)
    return list(reversed(xs))

for n in range(2, 41):
    print("Version {:2d}: {}".format(n, pattern(n)))

I'm looking for an algorithm where the magic branch & value is not needed The algorithm might not exist, but I'm hopeful.

share|improve this question

2 Answers 2

I don't think such algorithm exists, because I looked quite hard and couldn't find it. It seems you have to follow the given table. Your formula approximates it pretty well. Too bad about the magic branch, but this shouldn't be a major concern anyway: it's a small table that you only need to calculate once and can reuse later, so any performance issues should be negligible in practice.

Coding style

The coding style can be improved. Follow PEP8, the official coding style guide of Python, for example, put 2 blank lines in front of top-level method definitions

Unnecessary parentheses

The parentheses around the multiplication are unnecessary here:

w = 21 + ((ver - 1) * 4)       # Width

It would be better to use more meaningful variable names, for example no need to shorten version as ver.

Unnecessary parentheses here:

if (w == 145):

The augmented assignment operator +=

Instead of:

    intervals = intervals + (intervals % 2)

This is better:

    intervals += intervals % 2

Use one statement per line

Break the line after :, for example instead of:

for m in (n-1) * [intervals]: xs.append(xs[-1] - m)

Write like this:

for m in (n-1) * [intervals]: 
    xs.append(xs[-1] - m)

Avoid code in the global namespace

Move code out of the global namespace into methods, so instead of this:

for n in range(2, 41):
    print("Version {:2d}: {}".format(n, pattern(n)))

Do it this way:

def main():
    for n in range(2, 41):
        print("Version {:2d}: {}".format(n, pattern(n)))

if __name__ == '__main__':
    main()
share|improve this answer

I also don't see any way to avoid the exceptional case.

Your variables should have better names. If you avoid single-character names, then you could dispense with the comments.

The width formula could be simplified without losing any meaning.

The epilogue could also be simplified: repeatedly decreasing by a fixed interval is easily accomplished with range().

from math import ceil

def pattern(version):
    width = 17 + 4 * version
    (first, last) = (6, width - 6 - 1)
    span = last - first
    n = ceil(span / 28)

    interval = 2 * ceil(span / n / 2)           # Round up to multiple of 2
    if width == 145:                            # except version 32:
        interval = 26                           # instead of 28

    return [first] + list(reversed(range(last, 2 * first, -interval)))

if __name__ == '__main__':
    for version in range(2, 41):
        print("Version {:2d}: {}".format(version, pattern(version)))
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.