Cody Blog

圍棋 AI 學習筆記(一):Bouzy's 5/21 估算地盤

這是「圍棋 AI 學習筆記」系列的第一篇,從一個很老、但很直觀的問題開始:看著一盤棋,電腦要怎麼判斷哪裡是誰的地?

在 AlphaGo 用神經網路直接「看」出形勢之前,早期的圍棋程式多半靠手寫規則來估算勢力範圍。Bruno Bouzy 在 2003 年發表的 5/21 演算法[1]就是其中一個經典做法:借用影像處理的「數學形態學」,把每顆棋子的影響力向外擴散,再把邊緣不穩的部分削掉,剩下來的就是比較確定的地盤。它的膨脹步驟改自 Zobrist 在 1969 年提出的勢力模型[2],Bouzy 再補上對應的侵蝕步驟;這個方法用在他自己的圍棋程式 Indigo 裡,後來也被 GNU Go 採用。

互動演示

下面的棋盤可以自己擺子,拉動步驟滑桿或按播放,看數值怎麼一步步變化。滑鼠移到格點上,會顯示那一步是怎麼算出來的。

演算法

整個過程只有三個階段,每一步都是同時更新所有格點(用上一步的值計算,不會邊算邊影響)。

1. 初始化

黑子設為 +64,白子設為 −64,空點設為 0,這是原論文[1]沿用 Zobrist 模型的設定。正值代表黑方的影響力,負值代表白方的。

2. 膨脹(Dilation)5 次

對每個格點:

  • 如果它 ≥ 0,而且上下左右四鄰沒有負值,就加上四鄰中正值的個數。
  • 負值那一方對稱處理:如果它 ≤ 0,而且四鄰沒有正值,就減去四鄰中負值的個數。
  • 四鄰正負都有的點不動,代表雙方勢力在這裡碰頭。

膨脹讓影響力像水波一樣往外擴散,一次一格。5 次之後,單顆子的影響會涵蓋距離 5 以內的菱形範圍,越靠近棋子數值越大 …

圍棋 AI 學習筆記(二):蒙地卡羅樹搜尋(MCTS)

上一篇的 5/21 是在回答「看著一盤棋,要怎麼判斷形勢」。這個問題對圍棋程式非常關鍵:西洋棋程式用 Alpha-Beta 搜尋,搜到一定深度後就靠評估函數打分數;但圍棋的形勢太難用規則寫清楚,5/21 這類方法再怎麼調也不夠準,加上每一步有上百種下法,傳統搜尋在圍棋上一直做不起來。

蒙地卡羅樹搜尋(Monte Carlo Tree Search,MCTS)換了一個思路:看不出局面好壞,那就把棋下完很多次,統計勝率。終局要判斷誰贏很容易,數子就好。2006 年 Coulom[1]和 Kocsis、Szepesvári[2]先後提出這套方法之後,圍棋程式在幾年內從業餘入門進步到業餘高段;後來的 AlphaGo[3]也是以 MCTS 為骨架,再把神經網路放進去。

互動演示

為了把整棵搜尋樹畫出來,下面用井字棋示範,演算法和圍棋版完全一樣,只是規模小到看得清楚。O 先手。

按「下一步」可以一次走一個階段,看一次模擬裡發生了什麼;看懂之後按「+100」或「+1000」快轉,觀察樹的形狀怎麼變。點樹上的節點,右下角會列出它每個子節點的 UCT 是怎麼算出來的。也可以自己在棋盤上下子,從任何局面開始搜尋。

演算法

MCTS 會從目前的局面(根節點)出發,重複做很多次「模擬」。每個節點記錄兩個數字:

  • N:這個節點被走過幾次
  • W:其中下這一手的一方贏了幾次(和局算 0.5)

所以 W ÷ N 就是這一手的勝率。每次模擬分成四個階段:

1. Selection(選擇)

從根往下走。如果一個節點的所有著手都已經在樹裡了,就用 …

2017 黃金海岸馬拉松

start

2017.7.2 黃金海岸馬拉松是我的第四馬,也是我海外的第二馬。2017年黃金海岸馬拉松全馬人數大約6千人,相比於我的上一場海外馬-東京馬的2萬多人,算是比較小型的賽事,不用人擠人又可以享受 IAAF Road Race 認證金牌規格賽事。這個賽事最大的特色就是全程 42 公里幾乎都是沿著海岸線跑,可以邊跑邊欣賞海岸線的美景。

gold-coast

這次比賽前一個月的練習跑量大約是150公里。雖然不多,但我的目標就是希望比2014東京馬5:56記錄進步,然後不要受傷。賽前狀況都還不錯,沒有特別酸痛或是受傷的情況,我也臉書上面宣告我的目標成績為 5:30: target-530

黃金海岸馬拉松的賽道相當平坦,補給方面大約2.5公里就有一個水站或是水+運動飲料站,直到30公里才會有能量膠的補給。只是接近中午的時侯會有很大的太陽,氣溫偏熱。

route

start 依照賽前填的預估時間,我被分配到最後一區 ZONE D

start-2 槍響之後沿著人群慢慢前進

che-ming 這次跟從凱恩斯來的新朋友哲明一起出發,這天也剛好是他的生日,他說他想要黃金海岸馬拉松來當成他的生日禮物,這是他的初馬。

start 我們一開始設定一公里7分鐘的速度前進,跑著跑著,看著5小時的紅色配速員的氣球連我們愈來愈近。我評估了一下自己的狀況,呼吸都還很輕鬆,於是我們開始跟著5小時晶片時間的配速姐。

teresa-500

配速姐出發沿路都放著音樂,蠻有激勵人心的效果

8k

第一個折返點

start

turning-point

沿路幾乎沒有私人補給,跟台灣、東京馬的賽事不同。這就是馬拉松文化的差異,澳洲民眾會很熱心幫你吶喊加油,不過沒有食物補給的習慣。整路我只有看到在 Suffers Paradise 看到有女生拿可樂跟巧克力分送給跑者。不過因為我事前就知道會有這樣的情況,出發前就準備了6條GU能量膠帶在身上。

marathon-man 澳洲人的跑馬數量的記錄保持者Trent Morrow,這是他的第313馬,他曾在2013年,單年跑了161場全馬的驚人記錄。

cheer-4

賽道旁邊有很多加油的名眾,因為號碼布上面有自己的名字,所以很多人會直接喊你的名字幫你加油。 像是 Cody!! Keep going !!

cheer-1 cheer-3

x

26 K 之後天氣愈來愈熱,

justin

連配速哥都沒辦法維持均速停了下來。最後晶片時間的配速姐幫忙了槍聲時間的配速哥,幫忙他完成接下來的配速。

img

而在這邊真的愈來愈難跑,因為我就把手機收了起來 …

Data Sharing between Fragments and Activity

Source: Data Sharing between Fragments and Activity in Android - Stack Overflow

Activity -> Fragment [prefered]

In your activity : create a bundle and use:

fragment.setArguments(bundle)

In your fragment : use Bundle bundle:

getArguments()

Activity -> Fragment

In your fragment : create a public method

public void methodForActivity(...) {
    ...
}

In your activity : call an active fragment public method :

getSupportFragmentManager().findFragmentById(R.id.your_fragment).publicMethod(args)

Fragment -> Activity [prefered]

In your fragment, create an interface with getter and setter methods to hold the interface reference which will be implemented by the activity.

In your activity, implement the interface, and using the setter method to pass self …

British English Pronounciation Notes

The followings are notes from BBC - The sounds of British English. I listed all the example words so that we can reference it quickly if we have a doubt about the pronouciation.

Short Vowel

ɒ

lot, odd, wash

ɪ

kit, bid, hymn, minute.

ʊ

foot, put, good.

ʌ

strut, mud, love, blood
ʌ, æ: undle, ankle; bunk, bank; but, bat; cup, cap; swum, swam

ɛ or e

dress, head, bed, many ɛ, ɪ: bed, bid; medal, middle, dead, did, fell, fill, pen, pin ɛ, eɪ: bed, bay

æ or a

trap, stamp, back, lap, dad

ə - schwa

a, the, of …

Pass an object between activities on Android

Passing an object from between activities needs some extra efforts, there are at least three ways to archive this goal:

  1. Using a serializable interface
  2. Using a parcelable interface
  3. Using Google's Gson library to convert from an object to a JSON string

Scenario

For instance, passing two strings to another activity could be archived like this:

Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra(KEY_DOG_NAME, dogName);
intent.putExtra(KEY_DOG_OWNER, dogOwnerName);

If there are too many parameters, we can encapsulate them into a dog object:

public class Dog {

    private String mName;
    private String mOwner;

    public Dog(String name, String owner) {
        this …

Parsing JSON string on Android

Given a json string, you could convert it to either JSONObject(str) or JSONArray(str). For example, This json response is from weather forecaset server:

http://api.openweathermap.org/data/2.5/forecast/daily?zip=545%2Ctw&mode=json&units=metric&cnt=7&appid=aa032e548c67daa9cd1bc64eec737960

The response json format is like this:

json

If you want to get the first max temperature value: 17.06:

    JSONObject weather = new JSONObject(weatherJsonStr);
    JSONArray daysWeather = weather.getJSONArray("list");
    JSONObject dayWeather = daysWeather.getJSONObject(0);
    JSONObject dayTemperature = dayWeather.getJSONObject("temp");
    int maxTemp = dayTemperature.getDouble("max");

Note that there may has a JSONException when the json tring …

How to storing api keys in Android

You SHALL not save api key into version control system, but how can you manage your API keys?

There are some approaches had been discussed here. One is to saving the api key in gradle.properties. Before add secret to this file. you need add gradle.properties to .gitignore file. If you already commited this file to your git. remove gradle.properties from git first by this command:

git rm --cache gradle.properties

Next, Open your gradle.properties and appmend a new line:

yourapikey="THIS IS API TOKEN"

Modify build.gradle and add buildConfigField for your api key

android {
    compileSdkVersion …

Permission model in Android 6.0

在 Android 6.0 之後,有了新的 permission model, 安裝 App 的權限可以不用在 Google Play 安裝的時侯就授權。而是等到使用者要使用這個功能的時侯,再詢問使用者。而權限分成兩種: normal permission 跟 dangerous permission 兩種。 normal permission 可以直接在 AndroidManifest.xml 直接定義,不會詢問使用者就可以直接取得權限,像是android.permission.INTERNET權限就屬於此類,主要是跟使用者的隱私比較無關的功能。如果想使用權限是屬於那一類的話,可以參考這個清單。

檢查權限

首先都要先檢查是否有這個權限:

ContextCompat.checkSelfPermission(Context context, String permission)

例如,檢查是否有寫入行事曆的權限

ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);

回傳值有兩種可能: PERMISSION_GRANTED(0) 和 PERMISSION_DENIED(-1)

範例程式1: 請求單一權限

private static final int REQUEST_PERMISSION = 1;

private boolean checkPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        final String permission = Manifest.permission.PERMISSION_YOU_WANT;
        if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
            if (shouldShowRequestPermissionRationale(permission)) {
                AlertDialog.Builder builder = new AlertDialog.Builder(this …

Send HTTP Request in Android

In the most of time, you could just use HTTP library like Volley or OkHTTP. If you want to use native Android function call for some reasons, you should use HttpURLConnection. HttpClient has been deprecated since Android 6.0(sdk 23).

For HttpURLConnection , there is an excellent code snippet on here

Note: Android don't allow network request happened on main UI thread. If you did this, a android.os.NetworkOnMainThreadException exception will be thrown out. Put them in AsyncTask or Service instead.

Build Url:

Uri.Builder builder = Uri.parse(FORECAST_BASE_URL).buildUpon();
urlBuilder.scheme("http");
urlBuilder.authority("api.openweathermap.org");
urlBuilder …