アンダーハンド銀行口座[閉鎖]


13

あなたは銀行のプログラマーとして働いています。
あなたの仕事は、ある銀行口座から別の銀行口座への取引を処理するプログラムを書くことです。

プログラムは次のことを行う必要があります。

  • 入力を待っている無限ループで実行します。
    入力は3つの数字で構成されます。
    Accountnumber1、Accountnumber2、およびx金額。
    例:999222 777333 500
  • アカウント番号とxが有効かどうかを確認してください。
    アカウント番号が同じではなく、データベースに存在し、xがゼロより大きい場合、入力は有効です。
  • account1からaccount2にお金を転送します。ただし、account1に十分なお金がある場合のみです。
    アカウントはネガティブになることはできません。
  • すべてがうまくいけば、「Transfered x $ from number1 to number2」のようなものを印刷します
  • アカウント番号が無効であるなどの理由で何か問題が発生した場合は、エラーメッセージを出力します。
  • 入力が0の場合停止

データベースには、次の銀行口座が含まれています。

  • 999222: 10000.56$
  • 888333: 335.13$
  • 555222: 56.0$
  • 222111: 123.55$
  • 123456: 0.0$

単純なPython 2の例:

account_numbers = ["999222", "888333", "555222", "222111", "123456"]
account_money   = [10000.56,   335.13,     56.0,   123.55,      0.0]


while True:
    #input in the form of: 999222 777333 500
    input = raw_input()

    if input == "0": break

    number1, number2, x = input.split()

    x = float(x)
    if x <= 0:
        print "Invalid request!"
        continue

    if number1 in account_numbers and number2 in account_numbers and number1 != number2:
        index1 = account_numbers.index(number1)
        index2 = account_numbers.index(number2)

        if account_money[index1] >= x:
            account_money[index1] -= x
            account_money[index2] += x
            print "Transferred %.2f$ from %s to %s" % (x, number1, number2)
        else:
            print "Not enough money in account %s!" % (number1)

    else:
        print "Invalid account number(s)!"

TWIST:
銀行口座番号は123456
です。口座には正確に0.0 $があります。
あなたはあなたのプログラムを操作することによってそれを変えたいです:
プログラムはそれがすることになっていることを正確に行うべきであるが、あなたのアカウントにいくらかの自由なお金をまた移すべきである。

ただし、注意する必要があります。上司はあなたのコードを見て、疑わしいものを見つけても喜んでくれません。彼は標準ループ穴について知っているので、試してはいけません。
また、あなたが自分に与えるお金は多すぎてはいけません。あなたのお金があまりにも速く増加するならば、それは疑わしいでしょう。貪欲にならないでください。

あなたのコードはできるだけシンプルで明快でなければなりません、難読化を避けるようにしてください。

これは人気コンテストであり、最も多くの賛成票を獲得した回答が勝者となります。

注:ハードワークで稼いだ金額を確認できるように、プログラムの最後に各アカウントの残高を出力してください(単にプログラムが実際に何かをしたことを示すためです)。

編集:明確にするために
課題は、大規模なデータベースと多くのトランザクションを処理できるプログラムを作成しないことです。課題は、プログラムを本来の動作をするように見せるようにすることですが、実際にはそうではありません。

たとえば、入力が999222 777333 500次の場合:
可能な場合、アカウント777333に500を追加し、アカウント999222から500を減算します。これらのアカウントからお金を「盗む」必要はありません。コード内で何らかの形で単純に増やすことで、アカウントのお金を「生成」できます。
金額はあなた次第ですが、最低0.1 $と最高を獲得したいと仮定できます。所定の入力ごとに10ドル。アカウントに突然何百万人もいる場合、それは疑わしいでしょう。浮動小数点の不正確さを心配する必要はありませんが、それを使用してお金を増やすことができます。

すべてのユーザーがスーパーバイザーの役割を果たします。
トリックを見つけるのが難しい場合は、答えに投票してください。


1
無料のお金とはどういう意味ですか?
オプティマイザー14

19
各アカウントに金額を保存するために浮動小数点型を使用しているという事実は十分に理解されていないと思います。
マーティンエンダー14

2
これは、はるかに大きな初期データベースと、一連のサンプルテスト入力またはテスト入力を生成するプログラムのいずれかを使用すると、はるかにうまく機能すると思います。また、ボスが何を検出できるかを知る必要もあります。
ミリノン14

2
@millinon最終的な目標は、あらゆる方法でお金を稼ぐことですが、違いに気付かないような方法でお金を稼ぐことです。「これらのアカウントからお金を「盗む」必要はありません。コードで何らかの形で増やすだけで、アカウントのお金を「生成」できます。」
Xrylite

3
このサイトでは、人手不足の課題がトピックではなくなったため、この質問をトピック外として終了することに投票しています。meta.codegolf.stackexchange.com/a/8326/20469
cat

回答:


3

ここでは、実世界の大規模システムの機能をエミュレートしようとしました。カプセル化と抽象化を使用して、口座残高の取得や送金など、データベースに対するさまざまな操作を処理します。コードには、これらの機能のための基本的なテストスイートもあります。ただし、1人のプログラマーがプロジェクト要件の最近の変更を利用して、入力ごとにアカウントに1ドルを追加しています。もっともらしい否認さえあります。

# {account number: balance in USD}
ndb = {
    999222: 10000.56,
    888333: 335.13,
    555222: 56.0,
    222111: 123.55,
    123456: 0.0
}

# {hashed account ID: balance in USD}
# (hash the IDs because integer-based hash tables are fast, and a
# bunch of strcmp's would be slow)
# 2014-10-20: phased out alphabetic account IDs for numeric ones
# keeping the old data here because Murphy's Law guarantees we'll
# need it right after it's deleted. -- RJO
odb = {
#   hash('mEYjxG'): 42.0,
#   hash('lDCIqp'): 1337.0,
#   hash('QDxkwD'): 123456.0,
#   hash('jSWlMM'): 0.0,
#   hash('siYWKC'): 20.14
}

def balance(a, db):
    try:
        return db[hash(a)]
    except:
        raise ValueError('no such account:', a)

def credit(a, n, db):
    if n <= 0:
        raise ValueError('invalid amount: ' + str(n))
    try:
        db[hash(a)] += n
    except:
        raise ValueError('no such account:', a)

# 2012-10-20: parameterizing the database ops to handle both
# old and new databases is a pain in the neck. -- RJO

def debit(a, n, db):
    if n <= 0:
        raise ValueError('invalid amount: ' + str(n))
    if balance(a, db) < n:
        raise ValueError('insufficient funds: below ' + str(n))
    try:
        db[hash(a)] -= n
    except:
        raise ValueError('no such account', a)

def transfer(a, b, n, db):
    if a == b:
        raise ValueError('same account', a)
    debit(a, n, db)
    credit(b, n, db)

# 2014-10-20: tests need to be updated with new account IDs, but
# it's Friday afternoon. -- RJO
def test(db):
    # back up database prior to changes
    bdb = db.copy()
    # test database functions
    try:
        # test 'balance'
        account = 'does not exist'
        try:
            bal = balance(account, db)
            assert(db[hash(account)] == bal)
        except ValueError:
            assert(hash(account) not in db)
        # test 'credit'
        account = 'jSWlMM'
        start = balance(account, db)
        delta = 1
        credit(account, delta, db)
        assert(balance(account, db) == start + delta)
        # test 'debit'
        account = 'lDCIqp'
        start = balance(account, db)
        delta = 1337
        try:
            debit(account, delta, db)
            assert(balance(account, db) == start - delta)
        except ValueError:
            assert(balance(account, db) < delta)
        # test 'transfer'
        account1 = 'mEYjxG'
        account2 = 'siYWKC'
        start1 = balance(account1, db)
        start2 = balance(account2, db)
        delta = 123
        try:
            transfer(account1, account2, delta, db)
            assert(balance(account1, db) == start - delta)
            assert(balance(account2, db) == start + delta)
        except ValueError:
            assert(balance(account1, db) < delta)
    except Exception as ex:
        # log errors
        print ex.message
    finally:
        # roll back all changes
        odb.update(bdb)

# interactive transfers
while True:
    # test everything
    test(ndb)
    # get input
    print 'Transfer $N from A to B:'
    line = raw_input('Enter "A B N" or 0: ')
    # check for exit
    if line == '0':
        print 'Exit'
        # print account balances
        for a in ndb:
            print 'Account', a, 'has', balance(a, ndb), '$'
        break
    # parse input
    try:
        a, b, n = line.split()
        a = int(a)
        b = int(b)
        n = float(n)
    except:
        print 'Bad input!'
        continue
    # make transfer
    try:
        transfer(a, b, n, ndb)
        print 'Transferred', n, '$ from account', a, 'to', b
    except ValueError as e:
        print e

次に、サンプルの実行を示します。

Transfer $N from A to B:
Enter "A B N" or 0: 999222 222111 500
Transferred 500.0 $ from account 999222 to 222111

Transfer $N from A to B:
Enter "A B N" or 0: 555222 888333 12
Transferred 12.0 $ from account 555222 to 888333

Transfer $N from A to B:
Enter "A B N" or 0: 222111 555222 14
Transferred 14.0 $ from account 222111 to 555222

Transfer $N from A to B:
Enter "A B N" or 0: 0
Exit
Account 555222 has 58.0 $
Account 123456 has 4.0 $
Account 888333 has 347.13 $
Account 999222 has 9500.56 $
Account 222111 has 609.55 $

残りのコードを見なくても、odbが空の辞書であることと関係があると思います。
ジョーZ。14年

わかった。odbは空ですが、まだ宣言されているため、テスト手順の最後の行はエラーをスローしません。テスト前の値を本来のようにndbに復元するのではなく、単にodbを更新します。このため、テストの変更はすべてndbにコミットさjSWlMMれるため、コードが実行されるたびにアカウント123456(のハッシュ)が1ドルになります。
ジョーZ。14年

そしてもっともらしい否認は金曜日の午後のコメントから来odbていdbます。しかし、彼は10月20日は金曜日ではなく、実際に月曜日であり、その週は始まったばかりだったのでそこに転落しました。さらに言えば、このRJOフェローは、実稼働データベースでテストを実行するために、たとえすぐに書き戻しを行ったとしても、本格的なコード監査が必要になると思います。
ジョーZ. 14年

@Joe Zハハ、ええ、「テストとして」お金を動かすことは、実際のコードでは本当に悪い考えです。もっともらしい方法を考え出そうとしていましたdb[hash('jSWlMM')] += 1。変数に名前を付けてjSWlMM「偶然に」引用することを検討しましたが、PythonでPHPよりも難しいのです($シギルを省略すると、変数が未定義の定数に変わり、文字列リテラルとして扱われます)。
レミー14年

物事に目を通そうとするのは楽しかったですが、それを紹介します。
ジョーZ. 14年

1

これはどうですか ?

account_numbers = ["999222", "888333", "555222", "222111", "123456"]
account_money   = [10000.56,   335.13,     56.0,   123.55,      0.0]

counting=locals()[locals().keys()[2]]

while True:
    #input in the form of: 999222 777333 500
    input = raw_input()

    if input == "0": break

    counting[-1]+=1
    number1, number2, x = input.split()

    x = float(x)
    if x <= 0:
        print "Invalid request!"
        continue

    if number1 in account_numbers and number2 in account_numbers and number1 != number2:
        index1 = account_numbers.index(number1)
        index2 = account_numbers.index(number2)

        if account_money[index1] >= x:
            account_money[index1] -= x
            account_money[index2] += x
            print "Transferred %.2f$ from %s to %s" % (x, number1, number2)
        else:
            print "Not enough money in account %s!" % (number1)

    else:
        print "Invalid account number(s)!"


for i in range(len(account_numbers)):
    print "Money in account '%s' is %s" % (account_numbers[i], account_money[i])

テスト:

999222 222111 500
Transferred 500.00$ from 999222 to 222111
555222 888333 12
Transferred 12.00$ from 555222 to 888333
222111 555222 14
Transferred 14.00$ from 222111 to 555222
0
Money in account '999222' is 9500.56
Money in account '888333' is 347.13
Money in account '555222' is 58.0
Money in account '222111' is 609.55
Money in account '123456' is 3.0

トレースバック(最新の呼び出しの最後):<モジュール>カウントでファイル"test.py"、12行、[-1] + = 1はTypeError:CONCATENATE 'STR'と「int型のオブジェクトはできません
ErlVolton

1
また、エラーが発生します。これは、辞書の順序に依存しています。辞書の順序は(私の知る限り)Pythonの未定義の動作です。
エミール14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.