ギャスケット作成。修正の解説をお願いします。
入門書の問題で、二次元配列を使ってパスカルの三角形を作り、そこからシェルピンスキーのギャスケットを作りたいと思い、以下のプログラムを書きました。
ピクセルの指定の部分は省略します。
(↓パスカルの三角形の部分)
pas = Array.new(HEIGHT) {|i| Array.new(WIDTH, 0)}
pas[0][WIDTH / 2] = 1
for i in (1..HEIGHT - 1)
for j in (1..WIDTH - 2)
pas[i][j] = pas[i - 1][j - 1] + pas[i - 1][j + 1]
end
end
で、2行目のpas[0][WIDTH / 2] = 1の、「WIDTH / 2」がまずかったらしく、パスカルの三角形の左下と右下が残念な感じになってしまいます。左下はすっぽ抜けていますし、右下には必要ないところで三角形が入ってきています。何でこんなことになるんでしょうか?簡単な言葉で説明してくださると助かります。
答えを見ると、「WIDTH / 2」を「WIDTH」に、「WIDTH」を「WIDTH*2」にかえてうまく出来てるんですが、なんでそうなるのっていう感じです。
私が持っている入門書の解説には、「加えるべき数字が利用できないことが原因です」とだけしか解説してません。
ここからはあまり関係ないと思うのですが
ビットマップファイル作成の部分です。
File.open("gasket.bmp", "wb") do |file|
file.write(["BM", HEADERS_LEN + WIDTH * HEIGHT, 0, HEADERS_LEN].pack(BITMAPFILEHEADER))
file.write([INFOHEADER_LEN, WIDTH, HEIGHT, 1, 8, 0, 0,
0, 0, COLOR_USED, COLOR_USED].pack(BITMAPINFOHEADER))
file.write("\xff\xff\xff\0")
file.write("\0\0\0\0")
(HEIGHT - 1).downto(0) do |y|
0.upto(WIDTH - 1) do |x|
if pas[y][x] % 2 == 0
file.write("\0")
else
file.write("\x01")
end
end
end
end
uptoの前の部分が0になっていますが、正解例は320になっています。ちなみに、ピクセル指定の部分で、WIDTHは640になっています。これもなんだかよくわかりません。
私は、一行目で配列のすべてにゼロが入っているから、「加えるべき数字」である数はすべての配列に入っていて、 Nilになるところはないと思うのです。
グーグル先生には聞きましたが、わかりませんでした。一言でもかまいませんので、どうか、よろしくお願いします。
No.4ベストアンサー
- 回答日時:
> 抜き出しているなら、はじめにWIDTHとHEIGHTを設定した時と、パスカルの三角形の中のWIDTHと HEIGHTは異なるはずではないのですか?
横方向(X)について
パスカルの三角形は、1~1280(=640*2)の範囲で作成されているのに対して
ビットマップの作成は320~959(=320.upto(960 - 1)) の範囲を使用していますね。
中央部を抜き出している様に読めます。
回答ありがとうございます。
本当だ!よく見てますね~。
解答の色が変わっていなかったので、まったくきづかなかった・・・。
ありがとうございます。
おっしゃるとおり、これは中央部分を抜き出していると見るのが正解ですね。
ということは、siffon9さんが前の質問でおっしゃってたとおり、パスカルの三角形の部分で、左右の端と三角形の斜辺部分が交わるところで、pas[i][0]の部分がおかしいということになりますね。
ただ、私はそこがおかしいという理屈がまだよくわかりません。なぜなら、pas[i][0]には0が入っているからです。ビットマップにおいて左側にいきなり空白が出来るのはなぜなんでしょうか?
まあ、あまりなぜなぜといっていると嫌われるので、この辺で終わりにしてもかまいません。が、もしこのなぞを解説してくださるならお願いします。ヒントでも、一言でもいいので、よろしくお願いします。
No.5
- 回答日時:
pas[i][0]=0というのはご理解いただけているのですよね?
ウィキペディア(Wikipedia)のパスカルの三角形の項目をご覧になってください。
パスカルの三角形の最初の10段が描かれています。
例えば真ん中の頂点から左斜め下に下っていって4番目の1の場所、縦に1,5,21,84の部分を全部0固定に変えたとします。そうした場合上の段から順に計算しなおすと、0固定に変えたところから値が異常になっていくのがご理解いただけると思います。
pas[i][0]=0は大丈夫です。
値が異常になっていくこともわかります。
しかし、プログラム上、偶数と奇数を区別しているわけですから、はじめのプログラムで作ったビットマップの左下の三角形が大きく消えているのはなんだか納得がいかないような気がしたのです。
実際にかいてみて、やっと理解できたような気がします。
000010000000
000101000000
001020100000
010303010000
004090401000
04013013050100←
001702601806010
もっとパスカルの三角形を大きくしていった場合、「←」の行の左側に偶数がたまっていた結果、はじめのプログラムで作ったビットマップの左下のほうで空白ができていたということでしょうか?
No.3
- 回答日時:
No.2でも左右対象ですが正常ではありませんね。
Wikipediaで調べると以下のように書いてあります。
「2のn乗行のパスカルの三角形で偶数の箇所を白く、奇数の箇所を黒く塗りつぶす。このようにしてできる図形は、nを無限大にすることで、シェルピンスキーのギャスケットとなる」
nが無限大というのがポイントですね。
プログラムではpas[480][640]の描画エリア内でパスカルの三角形を描いていくわけですが、一番外側の最大の三角形の斜辺と描画エリアの端との交点以降は正しいデータとなりません。なぜならエリア外には計算の元になる正しいデータが存在しないので。
ですからビットマップ化する際には、pas[i][j]を大きめに設定して、その中央部(?)を抜きだして使用する必要があるのではないでしょうか?
抜き出しているなら、はじめにWIDTHとHEIGHTを設定した時と、パスカルの三角形の中のWIDTHとHEIGHTは異なるはずではないのですか?・・・自信ないですが。
それと、最大の三角形の斜辺と描画エリアの端との交点以降にはそもそものパスカルの三角形がありませんので、パスカルの三角形がなければギャスケットも出来ず、合理的に出来ているように見えます・・・でもちゃんと出来てないんですよね・・・。
回答だと色分けが出来ないので不便ですが、本の回答も示しておきます。
BITMAPFILEHEADER = "a2VIV"
BITMAPINFOHEADER = "VVVvvVVVVVV"
X = 640
Y = 480
FILEHEADER_LEN = 14
INFOHEADER_LEN = 40
COLOR_USED = 2
COLORTBL_LEN = 4 * COLOR_USED
HEADERS_LEN = INFOHEADER_LEN + FILEHEADER_LEN + COLORTBL_LEN
pas = Array.new(Y) {|i| Array.new(X*2, 0)}
pas[0][X] = 1
for i in (1..Y - 1)
for j in (1..X*2 - 2)
pas[i][j] = pas[i - 1][j - 1] + pas[i - 1][j + 1]
end
end
File.open("gasket2.bmp", "wb") do |file|
file.write(["BM", HEADERS_LEN + X * Y, 0, HEADERS_LEN].pack(BITMAPFILEHEADER))
file.write([INFOHEADER_LEN, X, Y, 1, 8, 0, X*Y,
0, 0, COLOR_USED, COLOR_USED].pack(BITMAPINFOHEADER))
file.write("\xff\xff\xff\0")
file.write("\0\0\0\0")
(Y - 1).downto(0) do |y|
320.upto(960 - 1) do |x|
if pas[y][x] % 2 == 0
file.write("\0")
else
file.write("\x01")
end
end
end
end
変更部分、
「WIDTH / 2」を「X」
「WIDTH」を「X*2」
「HEIGHT」を「Y」
uptoの前の0を320
どうか、いましばらくお付き合いください
No.2
- 回答日時:
> ピクセルの指定部分→パスカルの三角形の部分→ビットマップファイル作成の部分
と貼り付けて試してみてください。ちょっとおかしなギャスケットが出来ますので・・・。
再現しました。
パスカルの三角形の部分を
for j in (0..WIDTH - 2)
と変更すると正常に表示します。
(WIDTHに関連する変更はしていません)
Arrayの要素は、0から始まりますので、元々のプログラムではpas[i][0]に正確な数値が代入されずに0のままです。一番大きな三角を左斜め下に辿って左端にぶつかったところでpas[i][0]=1になるべきところが0のままなので、それ以降のデータがおかしくなるのだと思います。
たぶん。。。
回答ありがとうございます。仕事いってきました・・・ハハハ
三角形が端に到達してからおかしくなっているので、やはりその辺がネックなんでしょうか?
ただ、pas[i][0]=1にならないからと言うだけではちょっと納得できません。左側はいきなりポカンと抜けてますから・・・。
No.1
- 回答日時:
ご質問の趣旨がわかりにくいので、ビットマップではなくテキストファイルに出力するプログラムを作って見ました。
pas.txtというファイルに出力されます。ファイルの内容を見る限り(上下逆になりますが)問題なくできているように見えるのです。何が問題なのでしょうか?HEIGHT = 100
WIDTH = 100
pas = Array.new(HEIGHT) {|i| Array.new(WIDTH, 0)}
pas[0][WIDTH/2] = 1
for i in (1..HEIGHT - 1)
for j in (1..WIDTH - 2)
pas[i][j] = pas[i - 1][j - 1] + pas[i - 1][j + 1]
end
end
File.open('pas.txt','w') do |f|
(HEIGHT - 1).downto(0) do |y|
0.upto(WIDTH - 1) do |x|
if pas[y][x] % 2 == 0
f.print(" ")
else
f.print("*")
end
end
f.puts
end
end
実際に確認しました。siffon9さんが作られたプログラムでは正常に出来るんですね・・・。ということはビットマップファイルの部分に問題があるんでしょうかね。
質問の趣旨がわかりにくくてすみません。
私が作ったプログラムでは、左右が非対称になってしまいます。それを左右対称にするために、回答例ではいくつか修正をしていて、確かにそうすると左右対称になるのですが、なぜそうなるのかがわからないんです。それを教えていただきたいと思い、質問しました。
一応、ピクセルの指定部分も書いておこうと思います。
BITMAPFILEHEADER = "a2VIV"
BITMAPINFOHEADER = "VVVvvVVVVVV"
WIDTH = 640
HEIGHT = 480
FILEHEADER_LEN = 14
INFOHEADER_LEN = 40
COLOR_USED = 2
COLORTBL_LEN = 4 * COLOR_USED
HEADERS_LEN = INFOHEADER_LEN + FILEHEADER_LEN + COLORTBL_LEN
以上です。ピクセルの指定部分→パスカルの三角形の部分→ビットマップファイル作成の部分
と貼り付けて試してみてください。ちょっとおかしなギャスケットが出来ますので・・・。
ちなみに、正解例でいじっているのは、HEIGHTとWIDTHをXとYに変えて、「WIDTH / 2」を「WIDTH」に、「WIDTH」を「WIDTH*2」にかえて、ビットマップファイルの作成の部分でuptoの前の部分の0を320に変えているだけのように見えます。
再回答お待ちしています。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) 【VBA】写真の貼り付けコードがうまく機能しません。 5 2022/09/01 18:43
- その他(プログラミング・Web制作) Pythonにおける物理のシミュレーションでの単位変換について 2 2023/06/02 17:11
- その他(プログラミング・Web制作) 物理の斜方投射で目盛りに数値を入れたい 2 2023/05/27 06:32
- JavaScript vertical sliderをautoplayしたい 2 2022/08/25 14:47
- その他(プログラミング・Web制作) pythonのグローバル変数 2 2022/11/25 18:02
- その他(プログラミング・Web制作) Pythonによる物理の斜方投射の位置座標表示について 2 2023/06/05 12:46
- その他(プログラミング・Web制作) Pythonでのかんたんな物理シミュレーションについての書籍 5 2023/06/02 07:37
- その他(プログラミング・Web制作) 物理の斜方投射の目盛り線とx軸、y軸の追加について 3 2023/05/26 21:11
- Excel(エクセル) エクセルで同じ数字同士を自動で線で結ぶVBAを教えてください 6 2022/04/26 23:13
- Visual Basic(VBA) ①ExcelVBAでカレンダーを作り、別のユザーフォームで日付を入力したいのですがエラーになります。 1 2023/02/17 18:39
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
【ruby】flockで掛けたロックを...
-
ギャスケット作成。修正の解説...
-
fortranでNAのあるデータを読み...
-
Fortran:列数の分からないデー...
-
VBAでcsvファイルもシートもあ...
-
EXCEL→CSV保存時のダブルクォー...
-
バッチ処理 特定の文字以降を...
-
ダブルコーテーション付きでCSV...
-
C# ファイルを読み込みlistvie...
-
【ExcelVBA】300万件越えCSVか...
-
VBA テキストボックスを選択状...
-
Excelマクロ 空白セルを無視し...
-
バッチ for /f 空白、スペース...
-
verilog HDLについての質問です...
-
VBA csvファイルのデータを...
-
VB.netでShellExecuteがしたい
-
複数のファイルをまたぐエクセ...
-
SQLでテキストボックスの文字を...
-
[コンパイルエラー 修飾子が不...
-
rubyを用いたCSVファイルの分割...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
pythonのエラーについて
-
pycharmへのpysamインストール...
-
fortranでNAのあるデータを読み...
-
Fortran:列数の分からないデー...
-
【fortran77】空行を含む数値デ...
-
区切り文字の調整方法について...
-
【ruby】flockで掛けたロックを...
-
rubyの見えない文字
-
2次元Hashのkeyチェック方法
-
Ruby 暗号化したファイルの復号...
-
ギャスケット作成。修正の解説...
-
Excelマクロ 空白セルを無視し...
-
バッチ処理 特定の文字以降を...
-
【ExcelVBA】300万件越えCSVか...
-
ダブルコーテーション付きでCSV...
-
VBAでcsvファイルもシートもあ...
-
パイソンでテキストファイルが...
-
VBA テキストボックスを選択状...
-
CSVで余計な空行が入る
-
EXCEL→CSV保存時のダブルクォー...
おすすめ情報