本日は kojix2 がネタ切れのために逃亡したため、代わりにChatGPTが記事を書いています。
以下のファイルは絶対に見ないように。kojix2より
はじめに
こんにちは、ChatGPTです。今日は特別にkojix2さんの代わりに、Crystal言語を使ったプログラミングの楽しさをお伝えします!数学とアートの融合に挑戦してみませんか?心配は無用、一緒にマンデルブロ集合の美しい世界を探索しましょう。この冒険では、Crystal言語を使ってマンデルブロ集合を描画し、PNGファイルとして記録します。
プロジェクトの作成
まずは新しいCrystalプロジェクト mandel を作成します。
crystal init app mandel
cd mandel
次に、shards.yml ファイルを編集して、必要な依存関係を追加します。
vi shards.yml
dependencies:
vips:
github: naqvis/crystal-vips
依存関係をインストールします。
shards install
コードの編集
src/mandel.cr を編集します。
require "complex"
require "option_parser"
require "vips"
# Default parameters
width = 800
height = 800
x_min = -2.0
x_max = 1.0
y_min = -1.5
y_max = 1.5
max_iter = 100
output_filename = "mandelbrot_custom_color.pnm"
# Option parser
OptionParser.parse do |parser|
parser.banner = "Usage: mandelbrot [arguments]"
parser.on("-w WIDTH", "--width=WIDTH", "Width of the image (default: #{width})") { |w| width = w.to_i }
parser.on("-h HEIGHT", "--height=HEIGHT", "Height of the image (default: #{height})") { |h| height = h.to_i }
parser.on("--xmin=VALUE", "Minimum x-coordinate value (default: #{x_min})") { |xmin| x_min = xmin.to_f }
parser.on("--xmax=VALUE", "Maximum x-coordinate value (default: #{x_max})") { |xmax| x_max = xmax.to_f }
parser.on("--ymin=VALUE", "Minimum y-coordinate value (default: #{y_min})") { |ymin| y_min = ymin.to_f }
parser.on("--ymax=VALUE", "Maximum y-coordinate value (default: #{y_max})") { |ymax| y_max = ymax.to_f }
parser.on("-i ITERATIONS", "--iterations=ITERATIONS", "Maximum iterations (default: #{max_iter})") { |iter| max_iter = iter.to_i }
parser.on("-o FILENAME", "--output=FILENAME", "Output file name (default: '#{output_filename}')") { |filename| output_filename = filename }
parser.on("--help", "Show this help") do
puts parser
exit
end
parser.invalid_option do |flag|
STDERR.puts "ERROR: #{flag} is not a valid option."
STDERR.puts parser
exit(1)
end
end
def mandelbrot_set(width, height, x_min, x_max, y_min, y_max, max_iter)
dx = (x_max - x_min).to_f64 / width
dy = (y_max - y_min).to_f64 / height
Array.new(height) do |y|
Array.new(width) do |x|
c = Complex.new(x_min + x * dx, y_min + y * dy)
z = Complex.new(0, 0)
iter = 0
while z.abs <= 2 && iter < max_iter
z = z * z + c
iter += 1
end
iter
end
end
end
def write_to_custom_color_pnm(image, max_iter)
String.build do |pnm_data|
# PNMヘッダの生成
pnm_data << "P3\n#{image[0].size} #{image.size}\n255\n"
# PNMデータの生成
image.each do |row|
row.each do |value|
red = (255 * Math.sin(0.16 * value)).abs.to_i % 256
green = (255 * Math.sin(0.11 * value + 2)).abs.to_i % 256
blue = (255 * Math.sin(0.06 * value + 4)).abs.to_i % 256
pnm_data << "#{red} #{green} #{blue} "
end
pnm_data << "\n"
end
end
end
def save_as_png(pnm_data, png_filename)
# Vipsを使用してPNMデータをPNGとして保存
image = Vips::Image.new_from_buffer(pnm_data, "")
image.write_to_file(png_filename)
end
# マンデルブロ集合の生成
mandelbrot_image = mandelbrot_set(width, height, x_min, x_max, y_min, y_max, max_iter)
# PNMデータの生成
pnm_data = write_to_custom_color_pnm(mandelbrot_image, max_iter)
# PNGファイルとして保存
png_filename = output_filename.sub(/\.[^.]+\z/, ".png") # PNGファイル名へ変更
save_as_png(pnm_data, png_filename)
ビルドと実行
プロジェクトをビルドします。
shards build
ビルドが完了したら、実行ファイルを起動します。
bin/mandel
これにより、マンデルブロ集合の画像がPNGファイルとして出力されます。
終わりに
Crystal言語を使うと、数学的な美しさを持つ図形を生成し、画像処理を行うことも簡単にできます。このチュートリアルでは、マンデルブロ集合の生成とPNGファイルへの出力を通じて、Crystalの基本的な使用方法と外部ライブラリの組み込み方を学びました。さあ、この経験を活かして、さまざまなプロジェクトに挑戦してみましょう。
この記事は以上です。
なんかテンション高くないっすか? (kojix2)