isucon6で人権を失いました。

2016-09-18

はじめに

ISUCON6の予選に初日で参加しました。結果としては35000点くらいで人権を失いました。

<iframe src="//hatenablog-parts.com/embed?url=http://isucon.net/archives/48475110.html" title="ISUCON6 本選出場者決定のお知らせ : ISUCON公式Blog" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe>

昨年と一昨年と同じメンバーで今年も予選に参加しました。 前準備をいくつかしたのでその内容は来年のためにしたの方に残しておきます。

当日

はてなのキーワードやはてなスターみたいな問題でした。

お昼すぎまでGolangで動かすと0点で他チームが点数出てるので、とても焦っていました。

Golangの正規表現が辛いことがわかったのでhtmlifyないのコードの

re := regexp.MustCompile("("+strings.Join(keywords, "|")+")")
kw2sha := make(map[string]string)
content = re.ReplaceAllStringFunc(content, func(kw string) string {
	kw2sha[kw] = "isuda_" + fmt.Sprintf("%x", sha1.Sum([]byte(kw)))
	return kw2sha[kw]
})
content = html.EscapeString(content)
for kw, hash := range kw2sha {
	u, err := r.URL.Parse(baseUrl.String()+"/keyword/" + pathURIEscape(kw))
	panicIf(err)
	link := fmt.Sprintf("<a href=\"%s\">%s</a>", u, html.EscapeString(kw))
	content = strings.Replace(content, hash, link, -1)
}

のコードを

kw2sha := make(map[string]string, len(keywords))
for _, kw := range keywords {
	if strings.Contains(content, kw) {
		kw2sha[kw] = "isuda_" + fmt.Sprintf("%x", sha1.Sum([]byte(kw)))
		content = strings.Replace(content, kw, kw2sha[kw], -1)
	}
}
 
content = html.EscapeString(content)
for kw, hash := range kw2sha {
	u, err := r.URL.Parse(baseUrl.String() + "/keyword/" + pathURIEscape(kw))
	panicIf(err)
	content = strings.Replace(content, hash, fmt.Sprintf("<a href=\"%s\">%s</a>", u, html.EscapeString(kw)), -1)
}

のように一個ずつreplaceするように変更したところ1万点くらいのスコアが初めて出て一安心しました。

ただよくメッセージを見てみると1つずつやっているのでhash変換時の値に12などが含まれていた場合に再度変換されてしまうバグがありました。 またsha1等でわざわざ暗号化する必要もなかったので

kw2sha := make(map[string]string, len(keywords))
for _, kw := range keywords {
	if strings.Contains(content, kw) {
		kw2sha[kw] = "isuda_" + random()
		content = strings.Replace(content, kw, kw2sha[kw], -1)
	}
}
content = html.EscapeString(content)
for kw, hash := range kw2sha {
	u, err := r.URL.Parse(baseUrl.String() + "/keyword/" + pathURIEscape(kw))
	panicIf(err)
	content = strings.Replace(content, hash, fmt.Sprintf("<a href=\"%s\">%s</a>", u, html.EscapeString(kw)), -1)
}
var letterRunes = []rune("@#_=$%`~?!")

func random() string {
	b := make([]rune, 12)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

のようにkeywordに出てこなさそうな記号を元に乱数を作るようにしました。 上記の対応で3万点を超え出しました。

またその他に行ったこととして、

やろうと思ってできなかったこと

感想

今年はピザを冷まさず食べれた。

結果は悔しいので、来年こそ頑張る


前準備(チーム)

前準備(個人)

snipet作り

並列実行(待つ)

var wg sync.WaitGroup
for i:=0; i<10; i++ {
    wg.Add(1)
    go func(i int) {
        fmt.Println(i)
        wg.Done()
    }(i)
}
wg.Wait()

並列実行(待たない)

for i:=0; i<10; i++ {
    go func(i int) {
        fmt.Println(i)
    }(i)
}

使いそうなパッケージ

その他始まったら確認すること