LoginSignup
1
1

More than 5 years have passed since last update.

15パズル(作っただけ)

Posted at

問題

  • "レナとミナミの国際プログラミングコンテスト"から
  • こちらのサイト
  • 問題は「タイルをスライドさせ、盤面を完成させるプログラムを作成してください。」
  • このパズルの解き方知らないし解けないのでパズルが動くプログラム作りました

解答

poh5_plus.rb
# フィールドは縦4*横4
$ROW = 4
$COL = 4

# 4*4のフィールドを2次元配列で生成
$field_array  = Array.new($COL).map{ Array.new($ROW) }

# 正解データを格納する配列
$field_answer = Array.new($COL).map{ Array.new($ROW) }

# 空白タイルの場所を記憶するハッシュ
$blank_tile_point = {
  'row' => $ROW - 1,
  'col' => $COL - 1
}

# 移動回数をカウント
$move_count = 0

# 移動したいタイルの場所を記憶する配列
$move_tile_point = {
  'row' => -1,
  'col' => -1
}

# ルールを表示する関数
def print_rule()
  # 入力ルール
  puts "フィールド作成のルール"
  puts "4*4の計16マス"
  puts "16マスにはそれぞれ1〜15までの数字と'*'が入力できる"
  puts "入力の際は1行ずつ入力する"
  puts "それぞれのマスに入る数字(文字)は半角スペースで区切る"
end

# フィールドの初期状態を設定する関数
# 同時に正解データも生成
def set_field()
  answer_data = 0
  $COL.times do |count_col|
    print "#{count_col + 1}行目を入力"
    input_str = gets
    # 半角スペースで区切る
    input_info = input_str.split(" ")
    $ROW.times do |count_row|
      # フィールドに設定
      # ほんとはここで重複がないかの判定した方がいい
      $field_array[count_col][count_row]  = input_info[count_row]
      # アスタリスクだったら空白タイルとして場所を記憶
      if input_info[count_row] == "*" then
        $blank_tile_point['row'] = count_row
        $blank_tile_point['col'] = count_col
      end

      # 正解データを生成
      # 最後は16じゃなくてアスタリスク
      answer_data += 1
      answer_data = "*" if answer_data == 16
      $field_answer[count_col][count_row] = answer_data.to_s
    end
  end
end

# 現在のフィールドの状態を表示
def print_field()
  puts("------------")
  $COL.times do |count_col|
    $ROW.times do |count_row|
      printf("%2s", $field_array[count_col][count_row])
      print("|") unless count_row == 3
    end
    puts ""
    puts("------------")
  end
end

# 正解かどうか判定する関数
# 1箇所でも正解データと違ったらfalseをreturn
# 正解データと完全一致したらtrueをreturn
def judge_field()
  $COL.times do |count_col|
    $ROW.times do |count_row|
      unless $field_array[count_col][count_row] == "*" then
        # String型同士だと上手く比較できないのでint型に変換してから比較
        return false if ($field_array[count_col][count_row]).to_i != ($field_answer[count_col][count_row]).to_i
      end
    end
  end

  true
end

# 選択したタイルが動かせるか判定する関数
# 上下左右に空白タイルが存在するか調べる
# フィールドの外にアクセスしないように気をつける
def can_move_tile(move_tile)
  # 上に空白はあるか?
  unless $move_tile_point['col'].to_i == 0 then
    return true if $field_array[$move_tile_point['col'] - 1][$move_tile_point['row']] == "*"
  end

  # 下に空白はあるか?
  unless $move_tile_point['col'].to_i == 3 then
    return true if $field_array[$move_tile_point['col'] + 1][$move_tile_point['row']] == "*"
  end

  # 左に空白はあるか?
  unless $move_tile_point['row'].to_i == 0 then
    return true if $field_array[$move_tile_point['col']][$move_tile_point['row'] - 1] == "*"
  end

  # 右に空白はあるか?
  unless $move_tile_point['row'].to_i == 3 then
    return true if $field_array[$move_tile_point['col']][$move_tile_point['row'] + 1] == "*"
  end

  puts "そのタイルは移動できません"
  puts "もう一度選択してください"

  false
end

# 動かしたいタイルの場所を探す関数
def search_tile(move_tile)
  $COL.times do |count_col|
    $ROW.times do |count_row|
      unless $field_array[count_col][count_row] == "*" then
        if ($field_array[count_col][count_row]).to_i == move_tile.to_i then
          $move_tile_point['col'] = count_col
          $move_tile_point['row'] = count_row

          return true
        end
      end
    end
  end

  puts "そのタイルは存在しません"
  puts "もう一度選択してください"

  false
end

def judge_tile(move_tile)
  return false unless search_tile(move_tile)
  return false unless can_move_tile(move_tile)
  true
end

# swpa関数
# 空白タイルのマスと動かしたいマスの位置を入れ替える
def swap(move_tile_point, blank_tile_point)
  swap_array = {'row' => -1,'col' => -1}
  swap_array['col'] = move_tile_point['col']
  swap_array['row'] = move_tile_point['row']
  move_tile_point['col'] = blank_tile_point['col']
  move_tile_point['row'] = blank_tile_point['row']
  blank_tile_point['col'] = swap_array['col']
  blank_tile_point['row'] = swap_array['row']
end

# 中身を入れ替える関数
def change_tile(move_tile)
  $field_array[$move_tile_point['col']][$move_tile_point['row']]   = "*"
  $field_array[$blank_tile_point['col']][$blank_tile_point['row']] = move_tile

  swap($move_tile_point, $blank_tile_point)

  puts "#{move_tile}を移動"

  $move_count += 1  
  puts "#{$move_count}回目"
end

# ------------------------------
#        ここからメイン
# ------------------------------

# ルールの表示
print_rule()

# フィールドセット
set_field()

# 正解データと一致するまで無限ループ
until judge_field() do
  print_field()

  puts "移動したいタイルを選択してください"
  move_tile = gets.chomp

  # 選択したタイルが移動できるなら移動
  change_tile(move_tile) if judge_tile(move_tile)
end

puts "#{$move_count}回目で完成"

結果

フィールド作成のルール
4*4の計16マス
16マスにはそれぞれ1〜15までの数字と'*'が入力できる
入力の際は1行ずつ入力する
それぞれのマスに入る数字(文字)は半角スペースで区切る
1行目を入力1 2 3 4
2行目を入力8 7 6 5
3行目を入力9 11 12 10
4行目を入力15 * 13 14
------------
 1| 2| 3| 4
------------
 8| 7| 6| 5
------------
 9|11|12|10
------------
15| *|13|14
------------
移動したいタイルを選択してください
1
そのタイルは移動できません
もう一度選択してください
------------
 1| 2| 3| 4
------------
 8| 7| 6| 5
------------
 9|11|12|10
------------
15| *|13|14
------------
移動したいタイルを選択してください
98
そのタイルは存在しません
もう一度選択してください
------------
 1| 2| 3| 4
------------
 8| 7| 6| 5
------------
 9|11|12|10
------------
15| *|13|14
------------
移動したいタイルを選択してください
15
15を移動
1回目
------------
 1| 2| 3| 4
------------
 8| 7| 6| 5
------------
 9|11|12|10
------------
 *|15|13|14
------------

備考

  • コーディングなどの点でアドバイスなどいただければ幸いです
  • パズルは解ける気しないんでパズルの解法などはいらないです
1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1