#!/usr/bin/env python3
from itertools import permutations
from random import choice
import os , subprocess , sys
# カウンター最大値
max_count = 8
# データ
data = [ '' .join ( i) for i in permutations( '0123456789' , 4 ) ]
# メッセージ
msg = { 'at' : 'Please input \' Yes\' or \' No\' .' ,
'bc' : '{} bull{} and {} cow{}.' ,
'i' : 'Input: ' ,
'l' : 'Haha, you lose. It is {}.' ,
'n' : 'New Game?' ,
'p' : 's' ,
's' : '' ,
'v' : 'Please input a 4-digit defferent number.' ,
'w' : 'You win! 😊' }
# 情報
class Info( object ) :
def __init__ ( self , guess, result) :
self .guess = guess
self .result = result
def __repr__ ( self ) :
return f'Guess: {self.guess} Result: {self.result}'
# 環境
class Env( object ) :
def __init__ ( self , answer, flag, tries) :
self .answer = answer
self .flag = flag
self .tries = tries
def __repr__ ( self ) :
return f'Answer: {self.answer}, Flag: {self.flag}, Tries: {self.tries}'
# 初期化
def init( ) :
return Env( choice( data) , False , [ ] )
# ゲーム終了条件
def is_gameover( x, env) :
return x == env.answer or len ( env.tries ) + 1 == max_count
# 判定関数
def judge( x, env) :
bc = sum ( [ env.answer .count ( i) for i in x] )
bull = sum ( [ 1 if i[ 0 ] == i[ 1 ] else 0 for i in zip ( x, env.answer ) ] )
return bull, bc - bull
# Read
def read( env) :
x = input ( msg[ 'n' if env.flag else 'i' ] ) [ :4 ]
if env.flag or ( x.isdigit ( ) and len ( x) == 4 and x in data and x not in
[ i.guess for i in env.tries ] ) :
return x
else :
raise ValueError
# Eval
def interp( x, env) :
if env.flag :
x = x[ 0 ] .lower ( )
if x == 'y' :
return init( )
elif x == 'n' :
sys .exit ( )
else :
bull, cow = judge( x, env) # アンパック
return Env( env.answer ,
is_gameover( x, env) , # ゲーム終了条件を満たすか調べる
env.tries +
[ Info( x, msg[ 'bc' ] .format ( bull,
# 単数か複数か
msg[ 'p' if bull > 1 else 's' ] ,
cow,
# 単数か複数か
msg[ 'p' if cow > 1 else 's' ] ) ) ] )
# Print
def display( env) :
subprocess .run ( 'cls' if os .name == 'nt' else 'clear' )
# print(env) デバッグ用
[ print ( f'{i} {j}' ) for i, j in enumerate ( env.tries , 1 ) ]
if env.flag :
print ( msg[ 'w' ] if env.answer == env.tries [ -1 ] .guess else
msg[ 'l' ] .format ( env.answer ) )
return env
# REPL
if __name__ == '__main__' :
env = init( )
subprocess .run ( 'cls' if os .name == 'nt' else 'clear' )
while True :
try :
env = display( interp( read( env) , env) )
except AttributeError :
print ( msg[ 'at' ] )
except ValueError :
print ( msg[ 'v' ] )
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoKZnJvbSBpdGVydG9vbHMgaW1wb3J0IHBlcm11dGF0aW9ucwpmcm9tIHJhbmRvbSBpbXBvcnQgY2hvaWNlCmltcG9ydCBvcywgc3VicHJvY2Vzcywgc3lzCgojIOOCq+OCpuODs+OCv+ODvOacgOWkp+WApAptYXhfY291bnQgPSA4CgojIOODh+ODvOOCvwpkYXRhID0gWycnLmpvaW4oaSkgZm9yIGkgaW4gcGVybXV0YXRpb25zKCcwMTIzNDU2Nzg5JywgNCldCgojIOODoeODg+OCu+ODvOOCuAptc2cgPSB7J2F0JzogJ1BsZWFzZSBpbnB1dCBcJ1llc1wnIG9yIFwnTm9cJy4nLAogICAgICAgJ2JjJzogJ3t9IGJ1bGx7fSBhbmQge30gY293e30uJywKICAgICAgICdpJzogJ0lucHV0OiAnLAogICAgICAgJ2wnOiAnSGFoYSwgeW91IGxvc2UuIEl0IGlzIHt9LicsCiAgICAgICAnbic6ICdOZXcgR2FtZT8nLAogICAgICAgJ3AnOiAncycsCiAgICAgICAncyc6ICcnLAogICAgICAgJ3YnOiAnUGxlYXNlIGlucHV0IGEgNC1kaWdpdCBkZWZmZXJlbnQgbnVtYmVyLicsCiAgICAgICAndyc6ICdZb3Ugd2luISDwn5iKJ30KCiMg5oOF5aCxCmNsYXNzIEluZm8ob2JqZWN0KToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBndWVzcywgcmVzdWx0KToKICAgICAgICBzZWxmLmd1ZXNzID0gZ3Vlc3MKICAgICAgICBzZWxmLnJlc3VsdCA9IHJlc3VsdAogICAgZGVmIF9fcmVwcl9fKHNlbGYpOgogICAgICAgIHJldHVybiBmJ0d1ZXNzOiB7c2VsZi5ndWVzc30gUmVzdWx0OiB7c2VsZi5yZXN1bHR9JwoKIyDnkrDlooMKY2xhc3MgRW52KG9iamVjdCk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgYW5zd2VyLCBmbGFnLCB0cmllcyk6CiAgICAgICAgc2VsZi5hbnN3ZXIgPSBhbnN3ZXIKICAgICAgICBzZWxmLmZsYWcgPSBmbGFnCiAgICAgICAgc2VsZi50cmllcyA9IHRyaWVzCiAgICBkZWYgX19yZXByX18oc2VsZik6CiAgICAgICAgcmV0dXJuIGYnQW5zd2VyOiB7c2VsZi5hbnN3ZXJ9LCBGbGFnOiB7c2VsZi5mbGFnfSwgVHJpZXM6IHtzZWxmLnRyaWVzfScKCiMg5Yid5pyf5YyWCmRlZiBpbml0KCk6CiAgICByZXR1cm4gRW52KGNob2ljZShkYXRhKSwgRmFsc2UsIFtdKQoKIyDjgrLjg7zjg6DntYLkuobmnaHku7YKZGVmIGlzX2dhbWVvdmVyKHgsIGVudik6CiAgICByZXR1cm4geCA9PSBlbnYuYW5zd2VyIG9yIGxlbihlbnYudHJpZXMpICsgMSA9PSBtYXhfY291bnQKCiMg5Yik5a6a6Zai5pWwCmRlZiBqdWRnZSh4LCBlbnYpOgogICAgYmMgPSBzdW0oW2Vudi5hbnN3ZXIuY291bnQoaSkgZm9yIGkgaW4geF0pCiAgICBidWxsID0gc3VtKFsxIGlmIGlbMF0gPT0gaVsxXSBlbHNlIDAgZm9yIGkgaW4gemlwKHgsIGVudi5hbnN3ZXIpXSkKICAgIHJldHVybiBidWxsLCBiYyAtIGJ1bGwKCiMgUmVhZApkZWYgcmVhZChlbnYpOgogICAgeCA9IGlucHV0KG1zZ1snbicgaWYgZW52LmZsYWcgZWxzZSAnaSddKVs6NF0KICAgIGlmIGVudi5mbGFnIG9yICh4LmlzZGlnaXQoKSBhbmQgbGVuKHgpID09IDQgYW5kIHggaW4gZGF0YSBhbmQgeCBub3QgaW4KICAgICAgICAgICAgICAgICAgICBbaS5ndWVzcyBmb3IgaSBpbiBlbnYudHJpZXNdKToKICAgICAgICByZXR1cm4geAogICAgZWxzZToKICAgICAgICByYWlzZSBWYWx1ZUVycm9yCiAgICAgICAgICAgIAoKIyBFdmFsCmRlZiBpbnRlcnAoeCwgZW52KToKICAgIGlmIGVudi5mbGFnOgogICAgICAgIHggPSB4WzBdLmxvd2VyKCkKICAgICAgICBpZiB4ID09ICd5JzoKICAgICAgICAgICAgcmV0dXJuIGluaXQoKQogICAgICAgIGVsaWYgeCA9PSAnbic6CiAgICAgICAgICAgIHN5cy5leGl0KCkKICAgIGVsc2U6IAogICAgICAgIGJ1bGwsIGNvdyA9IGp1ZGdlKHgsIGVudikgIyDjgqLjg7Pjg5Hjg4Pjgq8KICAgICAgICByZXR1cm4gRW52KGVudi5hbnN3ZXIsCiAgICAgICAgICAgICAgICAgICBpc19nYW1lb3Zlcih4LCBlbnYpLCAjIOOCsuODvOODoOe1guS6huadoeS7tuOCkua6gOOBn+OBmeOBi+iqv+OBueOCiwogICAgICAgICAgICAgICAgICAgZW52LnRyaWVzICsKICAgICAgICAgICAgICAgICAgIFtJbmZvKHgsIG1zZ1snYmMnXS5mb3JtYXQoYnVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyDljZjmlbDjgYvopIfmlbDjgYsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNnWydwJyBpZiBidWxsID4gMSBlbHNlICdzJ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyDljZjmlbDjgYvopIfmlbDjgYsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNnWydwJyBpZiBjb3cgPiAxIGVsc2UncyddKSldKQoKIyBQcmludApkZWYgZGlzcGxheShlbnYpOgogICAgc3VicHJvY2Vzcy5ydW4oJ2NscydpZiBvcy5uYW1lID09ICdudCcgZWxzZSAnY2xlYXInKQogICAgIyBwcmludChlbnYpIOODh+ODkOODg+OCsOeUqAogICAgW3ByaW50KGYne2l9IHtqfScpIGZvciBpLCBqIGluIGVudW1lcmF0ZShlbnYudHJpZXMsIDEpXQogICAgaWYgZW52LmZsYWc6CiAgICAgICAgcHJpbnQobXNnWyd3J10gaWYgZW52LmFuc3dlciA9PSBlbnYudHJpZXNbLTFdLmd1ZXNzIGVsc2UKICAgICAgICAgICAgICBtc2dbJ2wnXS5mb3JtYXQoZW52LmFuc3dlcikpCiAgICByZXR1cm4gZW52CgojIFJFUEwKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICAgIGVudiA9IGluaXQoKQogICAgc3VicHJvY2Vzcy5ydW4oJ2NscydpZiBvcy5uYW1lID09ICdudCcgZWxzZSAnY2xlYXInKQogICAgd2hpbGUgVHJ1ZToKICAgICAgICB0cnk6CiAgICAgICAgICAgIGVudiA9IGRpc3BsYXkoaW50ZXJwKHJlYWQoZW52KSwgZW52KSkKICAgICAgICBleGNlcHQgQXR0cmlidXRlRXJyb3I6CiAgICAgICAgICAgIHByaW50KG1zZ1snYXQnXSkKICAgICAgICBleGNlcHQgVmFsdWVFcnJvcjoKICAgICAgICAgICAgcHJpbnQobXNnWyd2J10pCg==