關於 checkio.org

Posted by tjwei on 星期日, 12月 23, 2012 with No comments
checkio.org 是一個基於用寫程式來玩遊戲的網站,使用的語言是 python。剛開始,看起來就是一個有故事的 online judge 而已,只是加上一些類似遊戲的等級、成就的系統。
不過繼續玩下去,似乎會有一些變化、互動的題目(我只試了一下,所以還沒有真的碰到)。
但我的重點不是在介紹這個網站。
先介紹一個取巧的方式。一般來說,程式的題目會有點像是,下面這樣
# Withdraw without any incident 
# 120 - 10 - 0.5 - 1% = floor(109.4) = 109
# 109 - 20 - 0.5 - 1% = floor(88.3) = 88
# 88 - 30 - 0.5 - 1% = floor(57.2) = 57
from math import floor
def checkio(data):
    balance, withdrawal = data
    for a in (0.5+1.01*x for x in withdrawal if x%5==0):    
        balance = floor(balance-a) if balance >= a else balance            
    return balance

if __name__ == '__main__':
    assert checkio([120, [10 , 20, 30]]) == 57, 'First'

    # With one Insufficient Funds, and then withdraw 10 $
    assert checkio([120, [200 , 10]]) == 109, 'Second'

    #with one incorrect amount
    assert checkio([120, [3, 10]]) == 109, 'Third'

    assert checkio([120, [200, 119]]) == 120 , 'Fourth'

    assert checkio([120, [120, 10, 122, 2, 10, 10, 30, 1]]) == 56, "It's mixed all base tests"
    
    print('All Ok')

他會給你一個題目說明,你要寫個 checkio 函數來符合要求,除了上面給一些參考範例外,另外會用一堆資料來測試你的 checkio 函數。上面的程式碼是第一題 ATM 以及我的解答(雖然其實可以有公式解,但是花時間算公式沒意義)。
看出程式碼的問題了嗎?他讓你的 checkio 傳回一個東西來和標準答案比較。問題在於 python 有 operator overloading。所以下面這個寫法也可以通過。
class X(object):
    def __eq__(self,n):
        return True
    def __ne__(self,n):
        return False
def checkio(x):
    return X()

當然這很明顯是個作弊招數。之所以要 __ne__ 也 overload 的原因是,checkio 測試的程式碼其實和範例給的測試方式不同。而且實際上,上面這個作法只在少數的題目有效(ATM 有效,另外還有幾題也有效)。
原因是 checkio 檢查答案的方式有好幾種。有亂數或者固定測試,有類似範例但是用 != 的測試,也有用 json 傳回結果的測試。另外還有遊戲化的互動測試(僅供參考
,我不保證真實性)。
所以這只是一個有趣的小插曲,也不是我的重點。重點是, checkio 這個網站引起我的一些想法。
其中一個我覺得挺有趣的,是寫一個 python 的密室脫逃遊戲。什麼意思呢?可以把 restricted python shell 看成一個密室。有點像是古時候 python 的 rexec 或者 plone 等也有東西。總之,就是讓使用者在一個很有限制的 python 環境。熟悉 python 的人一定會說等等,rexec 不是因為有缺陷,所以被廢止移除了嗎?沒有錯,就是因為 python 太動態、靈活了,所以很多看起來限制重重的情形,其實都是逃脫的。當然我不是說一定沒辦法弄出完全安全 python 的限制環境,只是說當限制重重時,可以 python 玩家試著使用平常沒有發現的新玩法。
所以想像這樣,打開你的 idle ,然後 import puzzle, 會看到一段說明你被關在看似空無一物的 python 環境。然後你利用有限資源和  python 技巧逃出了這個 shell,卻又進入另外一個。然後你某些提示,解出一些問題,得到了 sin, cos, 以及 floor 函數,又利用這幾個函數,解決了令一個謎題,獲得了更多 module。
這樣想想,還挺有趣的。有點像是古時候的冒險類型遊戲,還要用文字輸入 open door 之類的指令,只不過現在你要用的語言是 python 而不是英文。
不過構思還不算完整,比方是否要有圖形?純 python 還是有一些謎題?
突然想到 checkio 本身不就是一個 restricted python 環境嗎,不如直接試試看手感,應該能更容易構思。於是上去試試看。結果發現可以奪回完整的 python 就算了,竟然還可以拿到 shell。這樣算是安全問題,所以就回報了 checkio。
目前感覺這個密室脫逃遊戲的構想是挺可行的。

更新:
checkio 方面有回應,有意更正安全漏洞。
Categories: