2012年5月22日火曜日

初めてのコンピュータサイエンス第7章解答

第7章の解答。以下ネタバレなので、読みたくない方は立ち去りましょう。全部あわせるとかなり長い解答です。問題文は載せませんので悪しからず。本は必要なら買いましょう。間違い(コード、英語)は指摘していただければ。よほどひどい解答が見つかったなら対応いたします。その前にこの章の個人的なメモ。

  • enumerateというシーケンスを受け取ると添え字とセットにして返す関数がある
  • x, y = 1, 2のような多重代入という仕組みがある。右辺は[1, 2]のようなリスト、文字列などシーケンスでも動作する。
  • ネストされたリストの長さが一定でない場合、ラグリスト(不規則リスト)と呼ばれる

1

問題文中の「前の値の2倍」というのは引数にとったリストの各要素を2倍しろという意味にとりました。もしかすると、1だけ小さい添え字のことを指しているのかもしれません。曖昧な問題文なのですが、一応解答をあげておきます。英語ではpreceeding valueを2倍なので、1つ前の添え字というよりも、処理前の要素と思うのですが...

def double_preceeding_correct(values):
    if values == []:
        pass
    else:
        values[0] = 0
        for i in range(1, len(values)):
            values[i] *= 2
    return values

print double_preceeding_correct([1, 2, 3])

2

rat1 = [23, 24, 22, 21, 22, 25, 26, 26, 23, 22]
rat2 = [21, 23, 24, 25, 26, 24, 24, 22, 21, 24]
# a)の解答
msg = "Rat %d weighed more than Rat %d on Day %d."
if rat1[0] > rat2[0]:
    print msg % (1, 2, 1) # 後から数値のみを付け加えることもできる
elif rat1[0] < rat2[0]:
    print msg % (2, 1, 1)
# b)の解答
if rat1[0] > rat2[0] and rat1[len(rat1)-1] > rat2[len(rat2)-1]:
    print "Rat 1 remained heavier than Rat 2."
else:
    print "Rat 2 became heavier than Rat 1."
# c)の解答
if rat1[0] > rat2[0]:
    if rat1[len(rat1)-1] > rat2[len(rat2)-1]:
        print "Rat 1 remained heavier than Rat 2."
    else:
        print "Rat 2 became heavier than Rat 1."

3~5

いずれも簡単な処理なので、一度にまとめて解答する。

print range(33, 50) # 3の解答

print range(10, 0, -1) # 4の解答、リストを降順にするには第3引数のステップ幅に負数を指定する

# 5の解答
total = 0
for num in range(2, 23):
    total += num

print float(total) / len(range(2,23)) # 整数/整数なので、切捨を避けるためfloatに変換しておく

6

もう少しコードを変形しすぎずに解答したいところなのですが...

def remove_neg_correct(num_list):
    '''num_listから正しく負数を取り除く'''
    result = []
    for item in num_list:
        if item >= 0:
            result.append(item)
    return result

aList = [1, 2, 3, -3, 6, -1, -3, 1]
result = remove_neg_correct(aList)
print result

7~8

def print_triangle_right(num):
    ''' Tを右三角形にして表示する'''
    for i in range(1, num+1):
        print 'T' * i

print_triangle_right(7)

def print_triangle_left(num):
    ''' Tを左三角形にして表示する'''
    for i in range(1, num+1):
        print ' ' * (num-i) + 'T' * i

print_triangle_left(7)

9

def print_triangle_right_while(num):
    ''' Tを右三角形にして表示する'''
    i = 1
    while i < num + 1:
        print 'T' * i
        i += 1

print_triangle_right_while(7)

def print_triangle_left_while(num):
    ''' Tを左三角形にして表示する'''
    i = 1
    while i < num + 1:
        print ' ' * (num -i) + 'T' * i
        i += 1

print_triangle_left_while(7)

10

rat_1_weight = 10
rat_2_weight = 10
rat_1_rate = 0.04
rat_2_rate = 0.04

# a)の解答
nWeek = 0
current_weight =  rat_1_weight
while True:
    nWeek += 1
    current_weight *= (rat_1_rate + 1)
    if current_weight > rat_1_weight * 1.25:
        break

print nWeek

# b)の解答
rat_2_rate = rat_1_rate + 0.03
rat1_current_weight = rat_1_weight
rat2_current_weight = rat_2_weight
nWeek = 0
while True:
    rat1_current_weight *= (rat_1_rate + 1.0)
    rat2_current_weight *= (rat_2_rate + 1.0)
    nWeek += 1
    if rat2_current_weight / rat1_current_weight > 1.1:
        break

print nWeek

11

import media

# 同じフォルダにあるマドレーヌの画像を利用している
madeleine = media.load_picture('pic207.jpg')
width, height = \
    media.get_width(madeleine), media.get_height(madeleine)

rotate = media.create_picture(height, width)
for y in range(0, height):
    for x in range(0, width):
        p_from = media.get_pixel(madeleine, x, y)
        p_to = media.get_pixel(rotate, height-y-1, x)
        media.set_color(p_to, media.get_color(p_from))

media.show(rotate)

12

a)の解答

import media

def swap_pix(pic, x1, y1, x2, y2):
    ''' swap color between (x1, y1) and (x2, y2) '''
    p1 = media.get_pixel(pic, x1, y1)
    p2 = media.get_pixel(pic, x2, y2)
    c1 = media.get_color(p1)
    c2 = media.get_color(p2)
    media.set_color(p1, c2)
    media.set_color(p2, c1)

def return_pic_size(pic):
    return media.get_width(pic), media.get_height(pic)

madeleine = media.load_picture('pic207.jpg')
width , height = return_pic_size(madeleine)

for y in range(0, height):
    for x in range(0, width/2):
        swap_pix(madeleine, x, y, width-x-1, y)

media.show(madeleine)

b)の解答。a)から改良を加えています。関数作成にこだわってみました。

import media

def swap_pix(pic, x1, y1, x2, y2):
    ''' swap color between (x1, y1) and (x2, y2) '''
    p1 = media.get_pixel(pic, x1, y1)
    p2 = media.get_pixel(pic, x2, y2)
    c1 = media.get_color(p1)
    c2 = media.get_color(p2)
    media.set_color(p1, c2)
    media.set_color(p2, c1)

def return_pic_size(pic):
    return media.get_width(pic), media.get_height(pic)

def y_axial_symmetry(pic):
    width , height = return_pic_size(madeleine)
    for y in range(0, height):
        for x in range(0, width/2):
            swap_pix(madeleine, x, y, width-x-1, y)

def x_axial_symmetry(pic):
    width , height = return_pic_size(madeleine)
    for y in range(0, height/2):
        for x in range(0, width):
            swap_pix(madeleine, x, y, x, height-y-1)

if __name__ == '__main__':
    madeleine = media.load_picture('pic207.jpg')
    x_axial_symmetry(madeleine)
    # y_axial_symmetry(madeleine)
    media.show(madeleine)

13

picを左上を基準にユークリッド距離でnピクセル離れた位置にある画素のみをサンプリングします。縮小した画像のサイズ計算が面倒ですね。

import math
import media

def down_scaling(pic, n):
    width, height = media.get_width(pic), media.get_height(pic)
    new_pic = media.create_picture(int(math.ceil(float(width)/n)),
                                   int(math.ceil(float(height)/n)))
    print new_pic.get_height(), new_pic.get_width()
    for y in range(height):
        for x in range(width):
            if y % n != 0 or x % n != 0:
                continue
            # print x, y, x/n, y/n
            p_from = media.get_pixel(pic, x, y)
            p_to = media.get_pixel(new_pic, x / n , y / n )
            target_col = media.get_color(p_from)
            media.set_color(p_to, target_col)

    return new_pic

if __name__ == '__main__':
    f = media.load_picture('pic207.jpg')
    ret = down_scaling(f, 2)
    media.show(ret)

14

問題よりも親切に10*10以外の平均値フィルタも実装しておりますが、端の処理だけは完全ではありません。問題の前提として、画像サイズは平均値フィルタの1辺のサイズで割り切れることを仮定しているため、これで解答としては十分と考えております。

import media

def fill_color(pic, x, y, n = 10):
    ''' make (x, y) to (x + n, y + n) rectangle pixels
        to the same color '''
    # print x, y
    r = g = b = 0
    for height in range(n):
        for width in range(n):
            a_pic = media.get_pixel(pic, x + width, y + height)
            r += media.get_red(a_pic)
            g += media.get_green(a_pic)
            b += media.get_blue(a_pic)
    r /= n*n
    g /= n*n
    b /= n*n
    set_color = media.create_color(r, g, b)
    for height in range(n):
        for width in range(n):
            a_pic = media.get_pixel(pic, x + width, y + height)
            media.set_color(a_pic, set_color)
    return pic

def mosaic_filter(pic, n = 10):
    ''' warning : edge is not processed if width and height is
        not divisible by n.
    '''
    width, height = media.get_width(pic), media.get_height(pic)
    for y in range(int(height/n)):
        for x in range(int(width/n)):
            fill_color(pic, x*n, y*n, n)
    return pic

if __name__ == '__main__':
    f = media.load_picture('pic207.jpg')
    mosaic_filter(f, 10)
    media.show(f)

15

ループをネストさせてモノクロイメージを作成する関数を作れという指示に従わない書き方もあるのですが、ここでは省略。create_monochrome_image関数の第2引数は3要素が必要で、それぞれr, g, bの重み付けに対応しています。全部同じ値にすればa)の解答、緑の重みを上げたのはb)の解答になります。重みはrgbからモノクロに変換する際によく使われる値を利用しています。実際のところ2種類でどの程度違うのかといわれると、私の目ではよく分からないところではありますが...

import media

def create_monochrome_image(pic, weight):
    ''' pic is picture to be processed.
        weight is weight for r, g, b values when we
        create monochrome image from color image.
        Default value should be [a, a, a], but
        green has more effective than other colors for human eyes,
        so when we take this fact into considaration,
        please change weight. ex.[a, 2a, a] (weight of green is hevier than that of others)
    '''
    s = float(sum(weight))
    for i in range(len(weight)):
        weight[i] /= s

    width, height = media.get_width(pic), media.get_height(pic)
    for y in range(height):
        for x in range(width):
            a_pic = media.get_pixel(pic, x, y)
            r = media.get_red(a_pic)
            g = media.get_green(a_pic)
            b = media.get_blue(a_pic)
            val = round(r * weight[0] + g * weight[1] + b * weight[2])
            col = media.create_color(val, val, val)
            media.set_color(a_pic, col)
    return pic

if __name__ == '__main__':
    f = media.load_picture('pic207.jpg')
    # create_monochrome_image(f, [1, 1, 1])
    create_monochrome_image(f, [0.299, 0.587, 0.114])
    media.show(f)

0 件のコメント:

コメントを投稿

フォロワー

ブログ アーカイブ

ページビューの合計