Pythonで数字のパズルを解いてみよう

パズルのルール

  1. 「A」という4ケタの数字と、「B」という5ケタの数字があります。
  2. 「B」は「A」の2倍です。つまり、「A」を2つ合わせると「B」になります。
  3. 「A」と「B」に使われている数字を全部集めると、1から9までの数字が1つずつ出てきます。

ルール3を満たす数には、例えば、こんな組み合わせがあります。

  • 例1: A=1834, B=29567
    • AとBを合わせると「183429567」になります。
    • この中に「1、2、3、4、5、6、7、8、9」が全部1つずつ入っています。

他にも例として

  • 例2: A=7462, B=14924
  • 例3: A=3478, B=95612

このパズルの答えをPythonを使って全部見つけてみましょう。

解き方を2つ説明します。

解き方(その1):Aを一つずつ試してみよう

最初の解き方は、4ケタの数字「A」を、1000から9999まで全部試してみる方法です。

ステップ1:AとBを表示してみよう

まず、Aの候補を1000から9999まで順番に作って、それぞれのAについてBを計算してみましょう。

Pythonのプログラムの中の、「#」で始まる部分は説明なので、書かなくてもプログラムは動きます。

print("--- ステップ1: AとBを表示してみよう ---")
# Aは1000から9999までなので、range(1000, 10000)と書きます。
# range(1000, 10000)は、1000から始まって9999で終わります。10000は含まれないんだ。
for A in range(1000, 10000):
    B = A * 2 # BはAの2倍なので、Aに2をかけるよ。
    print(f"A: {A}, B: {B}") # AとBを画面に出してみよう。

このプログラムを実行すると、たくさんのAとBの組み合わせが表示されるはずです。

ステップ2:Bが5ケタの数字か確認しよう

パズルのルールでは、Bは5ケタの数字でしたね。ステップ1で表示されたBの中には、4ケタや6ケタのBもあるかもしれません。5ケタじゃないBはパズルのルールに合わないから、次のAを試すようにプログラムを直しましょう。

print("\n--- ステップ2: Bが5ケタか確認しよう ---")
for A in range(1000, 10000):
    B = A * 2
    # Bが5ケタの数字かどうかは、Bが10000以上で、かつ100000未満かどうかで調べられます。
    if 10000 <= B < 100000:
        print(f"A: {A}, B: {B} (Bは5ケタなのでOK!)")

これで、Bが5ケタの組み合わせだけが表示されるようになりました。

ステップ3:AとBの数字をくっつけてCを作ろう

次に、AとBの数字を全部くっつけて「C」という一つの大きな数字の並びを作ってみましょう。ただし、数字のままくっつけることはできないので、一度「文字」に変えてからくっつけます。

print("\n--- ステップ3: AとBをくっつけてCを作ろう ---")
for A in range(1000, 10000):
    B = A * 2
    if 10000 <= B < 100000:
        # AとBを文字(文字列)に変えるよ。
        str_A = str(A)
        str_B = str(B)
        C = str_A + str_B # 文字列のAとBを足すと、くっつくんだ!
        print(f"A: {A}, B: {B}, C: {C}") # Cを表示してみよう。

Cには、AとBの数字が並んだ文字列が入っているはずです。

ステップ4:Cに1から9の数字が1つずつあるか確認しよう

最後に、Cの中に1から9の数字がすべて1つずつあるかを確認します。これには「セット(set)」という便利な機能を使います。セットは、数字や文字の「集まり」を作ってくれるもので、同じものは一つにまとめてくれます。

1から9までの数字のセットと、Cの数字のセットが同じなら、パズルの答えが見つかったことになります!

print("\n--- ステップ4: 1から9の数字が1つずつあるか確認しよう ---")
# パズルで使ってほしい数字の集まりを「正しいセット」として準備しておこう。
correct_digits_set = set('123456789')

for A in range(1000, 10000):
    B = A * 2
    if 10000 <= B < 100000:
        str_A = str(A)
        str_B = str(B)
        C = str_A + str_B

        # Cの中の数字のセットを作るよ。
        C_digits_set = set(C)

        # 正しいセットとCのセットが同じか調べるよ。
        if C_digits_set == correct_digits_set:
            print(f"見つけたよ! A = {A}, B = {B}")

これで、このパズルの答えが全部見つかるはずです!


解き方(その2):数字の並び替えから探してみよう

もう一つの解き方は、1から9までの数字を色々な順番に並べ替えてみて、そこからAとBを作る方法です。

この方法では、「順列(じゅんれつ)」というものを使います。順列とは、いくつかのものを順番に並べたものです。例えば、1, 2, 3の順列は「123」「132」「213」「231」「312」「321」などがあります。

ステップ1:1から9の数字のリストと順列を作ろう

まず、1から9までの数字をリストに入れて、そこから色々な順列を作ってみましょう。順列を作るには、itertoolsという特別な道具を使います。

import itertools # itertoolsという道具を使えるようにするよ

print("--- ステップ1: 1から9の数字のリストと順列を作ろう ---")
# 1から9までの数字のリストを作るよ。でも、順列を作るために「文字」にしておこう。
digits = ['1', '2', '3', '4', '5', '6', '7', '8', '9']

# digitsからすべての順列を作るよ。
# permutations(digits)は、digitsのすべての文字を並べ替えたものを作ってくれるんだ。
print("たくさんの順列が作られるよ!例えばこんな感じ:")
for p in itertools.permutations(digits):
    print(p)

プログラムを実行すると、数字がバラバラに並んだものがたくさん表示されるはずです。

ステップ2:順列をA用とB用に分けよう

次に、作った順列を、Aを作るための4つの数字と、Bを作るための5つの数字に分けましょう。

import itertools

print("\n--- ステップ2: 順列をA用とB用に分けよう ---")
digits = ['1', '2', '3', '4', '5', '6', '7', '8', '9']

count = 0
for p in itertools.permutations(digits):
    # pは例えば ('1', '2', '3', '4', '5', '6', '7', '8', '9') のようになっているよ。
    # 最初の4つをAの文字のリストにするよ。
    A_chars = p[0:4] # 0番目から3番目まで(合計4つ)
    # 残りの5つをBの文字のリストにするよ。
    B_chars = p[4:9] # 4番目から8番目まで(合計5つ)

    print(f"順列: {''.join(p)}, Aの文字: {''.join(A_chars)}, Bの文字: {''.join(B_chars)}")

これで、それぞれの順列が、Aになる部分とBになる部分に分けられたのがわかります。

‘’.join()という命令は、リストやタプルの要素を結合して文字列にするものです。

ステップ3:AとBの数字を作って表示しよう

Aの文字とBの文字ができたので、今度はそれらを数字に戻して、AとBを表示してみましょう。

import itertools

print("\n--- ステップ3: AとBの数字を作って表示しよう ---")
digits = ['1', '2', '3', '4', '5', '6', '7', '8', '9']

count = 0
for p in itertools.permutations(digits):
    A_chars = p[0:4]
    B_chars = p[4:9]

    # 文字のリストを一つの文字にして、それを数字(整数)に変えるよ。
    A = int(''.join(A_chars))
    B = int(''.join(B_chars))

    print(f"順列: {''.join(p)}, A: {A}, B: {B}")

これで、それぞれの順列から作られたAとBの数字が表示されるようになりました。

ステップ4:BがAの2倍か確認しよう

最後に、AとBが作れたら、BがAの2倍になっているか確認するだけです。もし「B == A * 2」が正しければ、それがパズルの答えになります。

import itertools

print("\n--- ステップ4: BがAの2倍か確認しよう ---")
digits = ['1', '2', '3', '4', '5', '6', '7', '8', '9']

print("パズルの答えを見つけているよ!")
found_count = 0
for p in itertools.permutations(digits):
    A_chars = p[0:4]
    B_chars = p[4:9]

    A = int(''.join(A_chars))
    B = int(''.join(B_chars))

    # BがAの2倍かどうかをチェック!
    if B == A * 2:
        print(f"見つけたよ! A = {A}, B = {B}")
        found_count += 1

if found_count == 0:
    print("ごめんね、この解き方では答えが見つからなかったみたい。")
else:
    print(f"合計で {found_count} 個の答えが見つかったよ!")