へたっぴpythonista

ド素人pythonistaとして、日々の学習成果や気づいたことについて書きます。

そろばん in python

数値とリストのインデックス値を組み合わせる練習でそろばんを作ってみました。

そろばん

def print_abacus(value): 

      a=len(str(value))
      num=['|00000*****   |','|00000****   *|','|00000***   **|','|00000**   ***|',
                '|00000*   ****|','|00000   *****|','|0000   0*****|','|000   00*****|',
                '|00   000*****|','|0   0000*****|']
      for i in range(10-a):

             print(num[0])            #入力された数字の桁数より大きい部分は0を表示する。
      for i in range(0,a):
             print(num[int(str(value)[i])])    #入力された数字を桁の大きい順に変換する。

 

numリストの中に0~9をそろばんで表現したものを入力して、そのインデックス値とvalueの各桁の数値を対応させることで答えを出力させます。最終行のnum[int(str(value)[i]])が汚いのがきになるなぁ。数値はインデクシングできないから文字列に変えて、でも文字列のままだとnumのインデクシングに使えないから再度数値に変えて・・・などと考えた結果こうなりましたが、後でもっといい方法を考えます、多分。

使用例

>>> print_abacus(123456789)
|00000*****   |
|00000****   *|
|00000***   **|
|00000**   ***|
|00000*   ****|
|00000   *****|
|0000   0*****|
|000   00*****|
|00   000*****|
|0   0000*****|
>>> print_abacus(253675)
|00000*****   |
|00000*****   |
|00000*****   |
|00000*****   |
|00000***   **|
|00000   *****|
|00000**   ***|
|0000   0*****|
|000   00*****|
|00000   *****|

 

リストのインデックス値と入力データの対応は例えばリストに画像URLを配置すれば、入力した値に対応した画像を表示させることができる等、なかなか応用の効きそうなテーマで面白いですね。

returnステートメントのある関数、ない関数をprintすると

関数をprint文で呼び出す際に、不必要なNoneが求めている返り値と一緒に返されるのが気になったので調べてみました。

Random 'None' output from basic python function - Stack Overflowを参考にしました。

結論から言えばreturnステートメントの有無が問題だったようです。returnステートメントは、実は呼び出されなかった場合に自動的に「見えない」Noneオブジェクトを返すという性質があります。だからreturnステートメントのない関数をprint文で呼び出すと、このNoneオブジェクトも一緒にprintされるのです。

 

つまり

def sum (a,b):

       print(a+b,='') という関数は実際には

 

def sum (a,b):

       print(a+b,end='')

       return None  であり、printするとa+b ,Noneが出力されるわけです。

 

関数において、基本的にreturnステートメントはあってもなくても良いですが、printで呼び出す関数については、不要なNoneを出力しないためにも、返り値はreturnステートメントで指定しましょう。

一行で書ける回文判定 in Python

Pythonを用いて一行で回文判定をします。

①素直に比べる

def palindrome(string): return 0 if string==string[::-1] else 1

 

元の文と、逆から読んだ文が一致するか否かを比べる、特に説明する必要のないコード。シンプルイズザベストですね。

②find関数を利用

def palindrome(string): return string.find(string[::-1])

 

find関数は文字列中から特定の語句を探して、その語句が最初に現れた位置を返す関数です。文字列が回文であった場合にはインデクス値0を、回文でなかった場合にはインデクス値-1を返します。

 

一行で書いてあると、見やすいし動作も早くなっていいですね。どれだけシンプルに掛けるかに頭を悩ませるレベルに早くなりたいものです(笑)自分はまだ、どうやってコードを書くかに頭を悩ませているので・・・

ProjectEuler28をpythonで解く

 寝る前に解いたら1時間近くかかってしまいました(笑)

 

Problem28

Starting with the number 1 and moving to the right in a clockwise direction a 5 by 5 spiral is formed as follows:

 21 22 23 24 25
 20  7    8    9 10 
 19  6    1    2 11
 18  5    4    3 12
 17 16 15 14 13

It can be verified that the sum of the numbers on the diagonals is 101.

What is the sum of the numbers on the diagonals in a 1001 by 1001 spiral formed in the same way?

 

1を中心にして、時計回りにぐるぐると数字を並べた時に、対角線上の数字(青い数字)の和はいくつか?という問題です。四角形の右上の数が1、9、25、・・・(2n+1)^2となっている点と、対角線上の数字同士の間隔が2、4、6、・・・2nと4つ毎に増加する点に注目して解いてみました。

解答

#-----------------------------------------------------------------------

def diagonals(width):
       ans=1
       max_add=(width-1)
       current=1
       add=2
       while add<=max_add:
            if width%2==0:            #widthは奇数でなくてはならない。  
                 break
            for i in range(1,5):

                 ans += current+(add*i)
                 current =current+(add*4)
                 add +=2
       print(ans)

diagonals(1001)

#-----------------------------------------------------------------------

関数diagonalsは変数を四角形の幅(一行に含まれる数字の数)とします。

3行目のmax_addは先述の数字同士の間隔(2n)と四角形の幅(2n+1)の関係から出した、間隔の最高値です。

6行目からのwhileループでは、間隔が4回置きに増加することを利用して、ansに値を足します。その後currentを更新し、間隔を2つ広げるコードを実行させます。

以上を実行すれば、答え669171001を得られます。

ProjectEuler18 をpythonで

久しぶりにEulerです。

Maximum path sum I

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

         3
      7    4
   2    4    6
 8   5    9    3

That is, 3 + 7 + 4 + 9 = 23.
Find the maximum total from top to bottom of the triangle below:


75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23

NOTE: As there are only 16384 routes, it is possible to solve this problem by trying every route. However, Problem 67, is the same challenge with a triangle containing one-hundred rows; it cannot be solved by brute force, and requires a clever method! ;o)

以前は日本語に翻訳されたウィキがあったのですが、いつの間にか無くなってしまっていたので本家の文章です。要するにピラミッド状に並んだ数字を上から順に足した和を求める問題です。因みにproblem67もこれとほぼ同じ問題なので、一緒に解答しておきました。

解答

#----------------------------------------------------------------------------

text=open('C:/python33/triangle.txt')
G=[ ]
for y in range(15):

    G.append([ ])
    for x in range(y+1):
          G[y].append(int(text.read(3)))

for y in range(14,0,-1):
      for x in range(y):
          if G[y][x]>G[y][x+1]:
              G[y-1][x] +=G[y][x]
          else:
              G[y-1][x] +=G[y][x+1]
print('ans is',G[0][0])

#----------------------------------------------------------------------------

まず、problem11の時と同じようにテキストを読み込み、リストを作成します。

次に和を求める方法ですが、上から順に足そうとするとどんどん枝分かれして処理量が多くなりそうだったので、下から順に足して、一番上に収束させることにしました。つまり、「ある1行の隣り合った2数のうち、大きい方だけをその上の行の数に足す」という方法をとることで、大幅に計算量を減らそうという魂胆です。

あとは答えをprintするコードを書いて完成です。

実行するとans is 1074となり正解を得ることができました。

また、2つあるfor y in range()の中味を各々100,99に変えて実行するとans is 7273となり、problem67の答えも得られます。

Eclipseでpygameを使う

pygameEclipseで使うには前回導入したインタープリタのライブラリにpygameを追加する必要があるようです。追加は前回インタープリタを設定した時と同じく、ウィンドウ⇒設定⇒インタープリタ-pythonで行います。使用するインタープリタを選択して、そのライブラリページの右上にある新規フォルダから追加します。

f:id:ruriohead:20130730192741p:plain

これだけのことですが、pygameやその他ライブラリを利用する時に必ずやらなくてはいけません。気をつけます、僕も。

Eclipse+Pydevの導入

今までIDLEしか使ったことが無かったけど、今後のことを考えるとEclipseが欲しいかなと思ったので導入してみます。

本体導入⇒日本語化⇒pydev導入の順でやろうと思ったら、日本語化・pydev導入済みのありがたいパッケージを発見したので利用させてもらいます。パッケージはwindows限定なので、MacやLinuxの方は同ページ内のプラグインを使う必要があるそうです。

Eclipse 日本語化 | MergeDoc Project

今はpygameの学習をメインにしてるので32bit版をダウンロードします。Full Editionにはpython本体も含まれています。既にpythonを持っているならばStandard Editionでもいいかもしれません(僕はダウンロードしてから気づきました・・・orz)

f:id:ruriohead:20130730174353p:plain

ダウンロードしたものを解凍して、Eclipseを起動すると・・・

f:id:ruriohead:20130730183825p:plain

このように始めから日本語化されたウィンドウが表示されます。Pydevの文字も確認できますね。

次にFull版ではデフォルトをpython2系から3系に直す必要があります。またStandard版の人は既存のpythonインタープリタを登録する必要があります。いずれもEclipse⇒ウィンドウ⇒設定⇒Pydev⇒インタープリタ-pythonで行います。

f:id:ruriohead:20130730190308p:plain

 

以上でEclipse+Pydevの導入・日本語化は完了です。