20200928のGoに関する記事は5件です。

Excelize 2.3.1がリリース–スプレッドシート(Excel)ファイル用のGoライブラリ、パスワードで保護されたスプレッドシートの読み取りをサポート

github.com/360EntSecGroup-Skylar/excelize

Excelize は、ECMA-376 Office OpenXML 標準に基づいて Office Excel ドキュメントを操作するための Go 言語で書かれたクラスライブラリです。 XLSX ファイルの読み書きに使用できます。Excelize は、他のオープンソースライブラリと比較して、イメージ(テーブル)付きのドキュメントの作成、Excel へのイメージの挿入、および保存後のチャートスタイルの保存をサポートしており、さまざまなレポートシステムに適用できます。

場合によっては、既存の Excel ドキュメントコンテンツの読み込み、新しい Excel ドキュメントの作成、既存のドキュメント(テンプレート)に基づく新しい Excel ドキュメントの生成、Excel ドキュメントへのイメージの挿入、チャートなどの Excel ドキュメントをプログラムで操作する必要があります。 テーブルなどの要素。プラットフォーム間でこれらの操作を実装する必要がある場合があります。Excelize はこれらのニーズを容易に満たすことができます。

オープンソース

GitHub: github.com/xuri/excelize

Doc: xuri.me/excelize/ja

リリースノート

このリリースで最も注目すべき変更は次のとおりです。

注目すべき機能

  • ECMA-376 ドキュメント標準暗号化によるパスワード保護付きのオープンスプレッドシートをサポートし、問題 #199 を関連付けます
  • ワークシートのチェックと制限を追加します
  • ピボットテーブル機能の拡張:ピボットテーブルのヘッダー、スタイル、およびテーブルオプションの設定をサポート
  • セキュリティの脆弱性とパッチ

互換性を向上させる

  • Go 1.15 と互換性があり、Windows でユニットテストが失敗し、潜在的な競合状態が発生します。問題#689を関連付けてください。
  • Apache Open Office および Kingsoft WPS™ とのデフォルトの行の高さの互換性
  • ふりがなのヒントとシートのタブの色の互換性を改善

バグの修正

  • 範囲外の RemoveRow スライスの境界を修正すると、場合によってはパニックが発生します。#686を解決してください。
  • ストリームライターが生成した破損したファイルの問題を修正する
  • 画像の追加が機能しないようにスケールを修正し、#691を解決します

雑多

  • エラー処理の改善と無効なスプレッドシートファイルを開いたときのクラッシュの修正
  • 多言語対応のドキュメント Web サイト:英語、フランス語、ロシア語、中国語、日本語、韓国語。更新されました。
  • Slack チャンネルに参加して、コミュニティの他のメンバーに会いにようこそ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Excelize 2.3.1 がリリース–スプレッドシート(Excel)ファイル用の Go ライブラリ、パスワードで保護されたスプレッドシートの読み取りをサポート

github.com/360EntSecGroup-Skylar/excelize

Excelize は、ECMA-376 Office OpenXML 標準に基づいて Office Excel ドキュメントを操作するための Go 言語で書かれたクラスライブラリです。 XLSX ファイルの読み書きに使用できます。Excelize は、他のオープンソースライブラリと比較して、イメージ(テーブル)付きのドキュメントの作成、Excel へのイメージの挿入、および保存後のチャートスタイルの保存をサポートしており、さまざまなレポートシステムに適用できます。

場合によっては、既存の Excel ドキュメントコンテンツの読み込み、新しい Excel ドキュメントの作成、既存のドキュメント(テンプレート)に基づく新しい Excel ドキュメントの生成、Excel ドキュメントへのイメージの挿入、チャートなどの Excel ドキュメントをプログラムで操作する必要があります。 テーブルなどの要素。プラットフォーム間でこれらの操作を実装する必要がある場合があります。Excelize はこれらのニーズを容易に満たすことができます。

オープンソース

GitHub: github.com/xuri/excelize

Doc: xuri.me/excelize/ja

リリースノート

このリリースで最も注目すべき変更は次のとおりです。

注目すべき機能

  • ECMA-376 ドキュメント標準暗号化によるパスワード保護付きのオープンスプレッドシートをサポートし、問題 #199 を関連付けます
  • ワークシートのチェックと制限を追加します
  • ピボットテーブル機能の拡張:ピボットテーブルのヘッダー、スタイル、およびテーブルオプションの設定をサポート
  • セキュリティの脆弱性とパッチ

互換性を向上させる

  • Go 1.15 と互換性があり、Windows でユニットテストが失敗し、潜在的な競合状態が発生します。問題#689を関連付けてください。
  • Apache Open Office および Kingsoft WPS™ とのデフォルトの行の高さの互換性
  • ふりがなのヒントとシートのタブの色の互換性を改善

バグの修正

  • 範囲外の RemoveRow スライスの境界を修正すると、場合によってはパニックが発生します。#686を解決してください。
  • ストリームライターが生成した破損したファイルの問題を修正する
  • 画像の追加が機能しないようにスケールを修正し、#691を解決します

雑多

  • エラー処理の改善と無効なスプレッドシートファイルを開いたときのクラッシュの修正
  • 多言語対応のドキュメント Web サイト:英語、フランス語、ロシア語、中国語、日本語、韓国語。更新されました。
  • Slack チャンネルに参加して、コミュニティの他のメンバーに会いにようこそ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Googleマップで宝探し!たんけんぼくのかそうまちゲーム

前々から温めてたのに実装方法が思いつかなかったんだけど、ようやくプロト出来た!

まえせつ

 自分の住んでいる町を迷路とかゲームのマップとして簡単に使えたら、遊び方が広がらないかなって思っててOpenStreetMap→Blender変換とかやってたけどうまくいかなくって。

 で、とある日、ぼーっとGoogleマップ見てたら

https://www.google.co.jp/maps/@35.6608375,139.7008749,3a,75y,43.91h,92.5t/data=!3m6!1e1!3m4!1sDrFpHa0VreQbapnpTC-QgA!2e0!7i16384!8i8192

あれ・・?このURLの"@"の後って緯度経度・・・?

!!!!!!!!

こっからの実装へのブレークスルーは実に早かった。

つくってみたわ

宝探しを通じて現実の町探検を仮想で楽しむゲームです。

goToMap4.gif

高解像度はこちら

  • Googleマップの緯度・経度を使って各プレイヤーのスタート地点とゴールを決めます
  • ゴールまでにヒントのテキストや、画像を仕掛けたりできます
  • プレイヤー同士でメッセージをやりとりしたり、書置きを読んだりできます

・Windows、Linux、Rasbian対応のGolang製Websocketサーバー

サーバーとするPCで動かしてください。

・Chrome拡張 (Chromiumも対応)

ゲームする端末上のChrome(と互換ブラウザ)で動かしてください。サーバーと同居できます。

じゅんび:

Googleマップで遊びたい町を開いてください。

url.png

こんなかんじでURL出ますんで下線の緯度経度をピックアップしてコンフィグを作ります。
コンフィグの例は以下です。

[PLAYER]
https://www.google.co.jp/maps/@35.6608375,139.7008749,3a,75y,43.91h,92.5t/data=!3m6!1e1!3m4!1sDrFpHa0VreQbapnpTC-QgA!2e0!7i16384!8i8192
https://www.google.co.jp/maps/@35.6613982,139.7001959,3a,75y,131.45h,104.53t/data=!3m6!1e1!3m4!1szZPFU_fUtAcf-e3DGysGlw!2e0!7i16384!8i8192

[GOAL]
35.6618983,139.7008538

[RESULT]
ゴールに着きました!

[ACTION]
35.6602069,139.7007403  マックに着きました~
35.6632348,139.701151   https://www.google.co.jp/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png
  • [PLAYER]はスタート地点です。URLをベタ貼りしてください。遊ぶ人数分貼ってください。
  • [GOAL]は目的地(ゴール)の緯度・経度を書いてください
  • [RESULT]はゴール時のメッセージです。httpから始まるURL指定で画像も指定できます
  • [ACTION]は緯度経度とメッセージをタブで区切ったもので来た時にメッセージ画像を表示します

緯度経度を調べながらヒント作ったり、画像貼ったりでゲームの"面"を作ってください

きどうほうほう:

 始めにGo言語のWebsocketサーバーを起動します。同フォルダにコンフィグ置いて実行すれば動きます。
 次にChrome拡張インストールします。ブラウザとサーバーが別PCの場合は拡張のアイコンを開いて「接続サーバー」欄にサーバーのIPアドレスとポート番号を指定してください。保存して拡張を再起動します。
 IPアドレスとポート番号はサーバー上に10秒に一回表示されます

1.png

join client!と出たら接続成功です。スタート地点のマップが自動的に開きます。

2.png

うごかしかた:

ルールとしては宝探しなのでGoogleマップで一番先に目的地に着けば良いです。その他は要素はゲーム装飾です。

3.png

コンフィグで指定した任意の場所でメッセージを出せます

4.png

任意の場所で画像も出せます

5.png

SNSぽく、参加者全員にメッセージを表示できます。

6.png

他プレイヤーにお知らせが出ました

7.png

特定の場所に書置きができます。メッセージ通知を後から追加できる機能です

8.png

あとがき

バーチャルリアリティはあくまで仮想の世界であってリアリティが今一つだと思ってる。
人がアバターになって出てきても、街という人の生活感が感じられる部分が薄いからと思ってる。
このゲームは現実の町で、仮想的に探検するという真逆の発想で産まれました。
たぶん他に無いアイディアなのでSNS化など、もっともっと育てたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Goの環境変数を扱う(viper)

はじめに

golangで環境設定ファイルを簡単にするライブラリとしてviperというものがあります。
今回はそのviperの使い方を簡単に紹介します

viper

シンプルにviperを使ってみる
今回は構造体にマッピングしてそれを引き回して使うように実装を行います

ソースツリー
.
├── config
│   ├── config.yaml
│   └── definition.go
└── main.go
config.yaml
# 環境変数設定用のyamlファイル
user: 
  name: "kosuke"

本来はデータベースのユーザー名等を入れることが多いですが、今回は簡単に上記のような環境変数を設定します。

definition.go
package config

import (
    "fmt"

    "github.com/spf13/viper"
)

// マッピング用の構造体
type Config struct {
    User User   `yaml:user`
}

type User struct {
    Name string `yaml:"name"`
}

func Load() (*Config, error) {
    viper.SetConfigName("config")   // 設定ファイル名を指定
    viper.SetConfigType("yaml")     // 設定ファイルの形式を指定
    viper.AddConfigPath("config/")  // ファイルのpathを指定

    err := viper.ReadInConfig()     // 設定ファイルを探索して読み取る
    if err != nil {            
        return nil, fmt.Errorf("設定ファイル読み込みエラー: %s \n", err)
    }

    var cfg Config

    err = viper.Unmarshal(&cfg)
    if err != nil {
        return nil, fmt.Errorf("unmarshal error: %s \n", err)
    }

    return &cfg, nil
}

Load()と言う関数の中で、環境変数のファイルを探しConfigという構造体に環境変数をマッピングしていきます

main.go
package main

import (
    "fmt"
    "viper-test/config"
)

func main() {
    cfg, err := config.Load()
    if err != nil {
        panic(err)
    }

    fmt.Println(cfg.User.Name)
}

今回は構造体にデータが入っていることを確かめるためにConfigの中身を表示しているだけですが、
本来であればこの構造体を引数に撮ってDBコネクション等を行っていきます。

$ go run main.go
kosuke

また、本番環境で運用等を行うときは外部から環境変数を受けとりたいということがあると思います。
その際は、、、

definition.go
package config

import (
    "fmt"

    "github.com/spf13/viper"
)

// マッピング用の構造体
type Config struct {
    User User   `yaml:user`
}

type User struct {
    Name string `yaml:"name"`
}

func Load() (*Config, error) {
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")
    viper.AddConfigPath("config/")

    // ===========↓追記=============
    // 環境変数がすでに指定されてる場合はそちらを優先させる
    viper.AutomaticEnv()            

    // データ構造をキャメルケースに切り替える用の設定
    viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
    // ===========↑ここまで=============

    err := viper.ReadInConfig()
    if err != nil {            
        return nil, fmt.Errorf("設定ファイル読み込みエラー: %s \n", err)
    }

    var cfg Config

    err = viper.Unmarshal(&cfg)
    if err != nil {
        return nil, fmt.Errorf("unmarshal error: %s \n", err)
    }

    return &cfg, nil
}

上記のような構文を使うことで環境変数が指定された時にはconfigファイルの値ではなく、
環境変数の値を参照することができます

# 環境変数を与えて `go run`
$ USER_NAME=tarou go run main.go
tarou

終わりに

今回はとてもシンプルな使い方でしたが、環境変数を構造体にマッピングして引き回していくのは余計な処理を書かなくて済むのてとても楽かなと思います。
もちろんですが、、、秘匿情報の扱い(AWSのアクセスキーなど)には気をつけて使用していきたいところです。

参考資料

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AtCoder Chokudai Contest 005 参戦記

AtCoder Chokudai Contest 005 参戦記

参加しなくていいかなあと思いつつ、結局参加してしまうやつ.

結果は49,656,737点で、AC 528人中240位でした. 最終コードは以下で Go 言語で提出しました.

package main

import (
    "bufio"
    "fmt"
    "math"
    "os"
    "strconv"
)

func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

func fill(d [][]byte, i, j int, x, y byte) {
    q := [][2]int{{i, j}}
    for len(q) != 0 {
        m, n := q[0][0], q[0][1]
        q = q[1:]
        d[m][n] = x
        if m > 0 {
            if d[m-1][n] == y {
                q = append(q, [2]int{m - 1, n})
            }
        }
        if m < N-1 {
            if d[m+1][n] == y {
                q = append(q, [2]int{m + 1, n})
            }
        }
        if n > 0 {
            if d[m][n-1] == y {
                q = append(q, [2]int{m, n - 1})
            }
        }
        if n < N-1 {
            if d[m][n+1] == y {
                q = append(q, [2]int{m, n + 1})
            }
        }
    }
}

//
var (
    N int
)

func main() {
    defer flush()

    _ = readInt()
    N = readInt()
    K := readInt()

    S := make([]string, N)
    for i := 0; i < N; i++ {
        S[i] = readString()
    }

    d := make([][]byte, N)
    for i := 0; i < N; i++ {
        d[i] = make([]byte, N)
    }

    result := make([][]string, 0, K)
    for n := 1; n <= K; n++ {
        x := byte(n + '0')
        t := make([]string, 0, 10000)

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                d[i][j] = S[i][j]
            }
        }

        for i := 1; i < N-1; i++ {
            for j := 1; j < N-1; j++ {
                if d[i][j] == x {
                    continue
                }

                a := 0
                b := 0
                if d[i-1][j] != d[i][j] {
                    a++
                    if d[i-1][j] == d[i+1][j] {
                        a++
                    }
                    if d[i-1][j] == d[i][j+1] {
                        a++
                    }
                } else if d[i][j-1] != d[i][j] {
                    b++
                    if d[i][j-1] == d[i+1][j] {
                        b++
                    }
                    if d[i][j-1] == d[i][j+1] {
                        b++
                    }
                }

                if a == 0 && b == 0 {
                    continue
                }

                var c byte
                if a >= b {
                    c = d[i-1][j]
                } else {
                    c = d[i][j-1]
                }
                t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, c))
                fill(d, i, j, c, d[i][j])
            }
        }

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                if d[i][j] == x {
                    continue
                }

                t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, x))
                fill(d, i, j, x, d[i][j])
            }
        }
        result = append(result, t)
    }

    best := math.MaxInt64
    for i := 0; i < K; i++ {
        best = min(best, len(result[i]))
    }

    bestIndex := -1
    for i := 0; i < K; i++ {
        if len(result[i]) == best {
            bestIndex = i
            break
        }
    }

    println(best)
    for i := 0; i < best; i++ {
        println(result[bestIndex][i])
    }
}

const (
    ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
    result := bufio.NewScanner(os.Stdin)
    result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
    result.Split(bufio.ScanWords)
    return result
}()

func readString() string {
    stdinScanner.Scan()
    return stdinScanner.Text()
}

func readInt() int {
    result, err := strconv.Atoi(readString())
    if err != nil {
        panic(err)
    }
    return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
    stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
    return fmt.Fprintln(stdoutWriter, args...)
}

感想、反省点など

タイムライン

以下は大まかなタイムラインです.

  • [21:00] YouTube で動画見てた(ぉぃ).
  • [21:07] アァァ! となって急いで https://atcoder.jp/ にアクセスした.
  • [21:07] 一応 checker.zip を拾って斜め読みした.
  • [21:12] 問題文を読んで、何もしなくても一応 AC はするんだなと思い、以下を提出して5807500点をゲット.
    id, N, K = map(int, input().split())
    S = [input() for _ in range(N)]

    print(0)
  • [21:25] 取り敢えず最初に一番多い色に塗りつぶすかと思い、以下を提出して49558075点をゲット.
from collections import Counter

id, N, K = map(int, input().split())
S = [input() for _ in range(N)]

c = Counter()
for i in range(N):
    c.update(S[i])
x = c.most_common(1)[0][0]

result = []
for i in range(N):
    for j in range(N):
        if S[i][j] != x:
            result.append('%d %d %s' % (i + 1, j + 1, x))
print(len(result))
print(*result, sep='\n')
  • [21:37] 左と上が同じ色の場合は既に塗る必要がないなと思い、以下を提出して49649188点をゲット.
from collections import Counter

id, N, K = map(int, input().split())
S = [input() for _ in range(N)]

c = Counter()
for i in range(N):
    c.update(S[i])
x = c.most_common(1)[0][0]

result = []
for i in range(N):
    for j in range(N):
        if S[i][j] != x and (i == 0 or S[i][j] != S[i - 1][j]) and (j == 0 or S[i][j] != S[i][j - 1]):
            result.append('%d %d %s' % (i + 1, j + 1, x))
print(len(result))
print(*result, sep='\n')
  • [21:42] 別に全色試してもいいんじゃねって気づき、以下を提出して49649427点をゲット. 99位.
id, N, K = map(int, input().split())
S = [input() for _ in range(N)]

result = []
for n in range(1, K + 1):
    x = str(n)
    t = []
    for i in range(N):
        for j in range(N):
            if S[i][j] != x and (i == 0 or S[i][j] != S[i - 1][j]) and (j == 0 or S[i][j] != S[i][j - 1]):
                t.append('%d %d %s' % (i + 1, j + 1, x))
    result.append(t)

best = min(len(result[i]) for i in range(K))
for i in range(K):
    if len(result[i]) == best:
        best_index = i
        break

print(len(result[best_index]))
print(*result[best_index], sep='\n')
  • [22:13] 塗るシミュレーションをしたいなと思い、Go 言語に移植し完了する.
  • [22:22] 塗るシミュレーションを入れたコードを提出し、49654250点をゲット. 184位.
package main

import (
    "bufio"
    "fmt"
    "math"
    "os"
    "strconv"
)

func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

func main() {
    defer flush()

    _ = readInt()
    N := readInt()
    K := readInt()

    S := make([]string, N)
    for i := 0; i < N; i++ {
        S[i] = readString()
    }

    d := make([][]byte, N)
    for i := 0; i < N; i++ {
        d[i] = make([]byte, N)
    }

    result := make([][]string, 0, K)
    for n := 1; n <= K; n++ {
        x := byte(n + '0')
        t := make([]string, 0, 10000)

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                d[i][j] = S[i][j]
            }
        }

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                if d[i][j] != x {
                    s := fmt.Sprintf("%d %d %c", i+1, j+1, x)
                    t = append(t, s)
                    y := d[i][j]
                    q := [][2]int{[2]int{i, j}}
                    for len(q) != 0 {
                        m, n := q[0][0], q[0][1]
                        q = q[1:]
                        d[m][n] = x
                        if m > 0 {
                            if d[m-1][n] == y {
                                q = append(q, [2]int{m - 1, n})
                            }
                        }
                        if m < N-1 {
                            if d[m+1][n] == y {
                                q = append(q, [2]int{m + 1, n})
                            }
                        }
                        if n > 0 {
                            if d[m][n-1] == y {
                                q = append(q, [2]int{m, n - 1})
                            }
                        }
                        if n < N-1 {
                            if d[m][n+1] == y {
                                q = append(q, [2]int{m, n + 1})
                            }
                        }
                    }
                }
            }
        }
        result = append(result, t)
    }

    best := math.MaxInt64
    for i := 0; i < K; i++ {
        best = min(best, len(result[i]))
    }

    bestIndex := -1
    for i := 0; i < K; i++ {
        if len(result[i]) == best {
            bestIndex = i
            break
        }
    }

    println(best)
    for i := 0; i < best; i++ {
        println(result[bestIndex][i])
    }
}

const (
    ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
    result := bufio.NewScanner(os.Stdin)
    result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
    result.Split(bufio.ScanWords)
    return result
}()

func readString() string {
    stdinScanner.Scan()
    return stdinScanner.Text()
}

func readInt() int {
    result, err := strconv.Atoi(readString())
    if err != nil {
        panic(err)
    }
    return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
    stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
    return fmt.Fprintln(stdoutWriter, args...)
}
  • [23:00] 先に離れている島を繋げておけば、繋ぐたびに1点増えるなと思った. 繋げるパスを追加して提出し、49654387点をゲット. 205位.
package main

import (
    "bufio"
    "fmt"
    "math"
    "os"
    "strconv"
)

func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

func fill(d [][]byte, i, j int, x, y byte) {
    q := [][2]int{{i, j}}
    for len(q) != 0 {
        m, n := q[0][0], q[0][1]
        q = q[1:]
        d[m][n] = x
        if m > 0 {
            if d[m-1][n] == y {
                q = append(q, [2]int{m - 1, n})
            }
        }
        if m < N-1 {
            if d[m+1][n] == y {
                q = append(q, [2]int{m + 1, n})
            }
        }
        if n > 0 {
            if d[m][n-1] == y {
                q = append(q, [2]int{m, n - 1})
            }
        }
        if n < N-1 {
            if d[m][n+1] == y {
                q = append(q, [2]int{m, n + 1})
            }
        }
    }
}

//
var (
    N int
)

func main() {
    defer flush()

    _ = readInt()
    N = readInt()
    K := readInt()

    S := make([]string, N)
    for i := 0; i < N; i++ {
        S[i] = readString()
    }

    d := make([][]byte, N)
    for i := 0; i < N; i++ {
        d[i] = make([]byte, N)
    }

    result := make([][]string, 0, K)
    for n := 1; n <= K; n++ {
        x := byte(n + '0')
        t := make([]string, 0, 10000)

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                d[i][j] = S[i][j]
            }
        }

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                if d[i][j] != x {
                    if i > 0 && d[i-1][j] != d[i][j] {
                        s := fmt.Sprintf("%d %d %c", i+1, j+1, d[i-1][j])
                        t = append(t, s)
                        fill(d, i, j, d[i-1][j], d[i][j])
                    } else if j > 0 && d[i][j-1] != d[i][j] {
                        s := fmt.Sprintf("%d %d %c", i+1, j+1, d[i][j-1])
                        t = append(t, s)
                        fill(d, i, j, d[i][j-1], d[i][j])
                    }
                }
            }
        }

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                if d[i][j] != x {
                    s := fmt.Sprintf("%d %d %c", i+1, j+1, x)
                    t = append(t, s)
                    fill(d, i, j, x, d[i][j])
                }
            }
        }
        result = append(result, t)
    }

    best := math.MaxInt64
    for i := 0; i < K; i++ {
        best = min(best, len(result[i]))
    }

    bestIndex := -1
    for i := 0; i < K; i++ {
        if len(result[i]) == best {
            bestIndex = i
            break
        }
    }

    println(best)
    for i := 0; i < best; i++ {
        println(result[bestIndex][i])
    }
}

const (
    ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
    result := bufio.NewScanner(os.Stdin)
    result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
    result.Split(bufio.ScanWords)
    return result
}()

func readString() string {
    stdinScanner.Scan()
    return stdinScanner.Text()
}

func readInt() int {
    result, err := strconv.Atoi(readString())
    if err != nil {
        panic(err)
    }
    return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
    stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
    return fmt.Fprintln(stdoutWriter, args...)
}
  • [23:15] 繋げるパスが上優先で、上が駄目な時に左となっていて、左が得そうな時に損なので、スコアリングして上か左か決めるように書いたが、今見るとバグっていて動作していない. でもなぜか提出したら点が増えて、49656737点をゲット. 221位.
package main

import (
    "bufio"
    "fmt"
    "math"
    "os"
    "strconv"
)

func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

func fill(d [][]byte, i, j int, x, y byte) {
    q := [][2]int{{i, j}}
    for len(q) != 0 {
        m, n := q[0][0], q[0][1]
        q = q[1:]
        d[m][n] = x
        if m > 0 {
            if d[m-1][n] == y {
                q = append(q, [2]int{m - 1, n})
            }
        }
        if m < N-1 {
            if d[m+1][n] == y {
                q = append(q, [2]int{m + 1, n})
            }
        }
        if n > 0 {
            if d[m][n-1] == y {
                q = append(q, [2]int{m, n - 1})
            }
        }
        if n < N-1 {
            if d[m][n+1] == y {
                q = append(q, [2]int{m, n + 1})
            }
        }
    }
}

//
var (
    N int
)

func main() {
    defer flush()

    _ = readInt()
    N = readInt()
    K := readInt()

    S := make([]string, N)
    for i := 0; i < N; i++ {
        S[i] = readString()
    }

    d := make([][]byte, N)
    for i := 0; i < N; i++ {
        d[i] = make([]byte, N)
    }

    result := make([][]string, 0, K)
    for n := 1; n <= K; n++ {
        x := byte(n + '0')
        t := make([]string, 0, 10000)

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                d[i][j] = S[i][j]
            }
        }

        for i := 1; i < N-1; i++ {
            for j := 1; j < N-1; j++ {
                if d[i][j] == x {
                    continue
                }

                a := 0
                b := 0
                if d[i-1][j] != d[i][j] {
                    a++
                    if d[i-1][j] == d[i+1][j] {
                        a++
                    }
                    if d[i-1][j] == d[i][j+1] {
                        a++
                    }
                } else if d[i][j-1] != d[i][j] {
                    b++
                    if d[i][j-1] == d[i+1][j] {
                        b++
                    }
                    if d[i][j-1] == d[i][j+1] {
                        b++
                    }
                }

                if a == 0 && b == 0 {
                    continue
                }

                var c byte
                if a >= b {
                    c = d[i-1][j]
                } else {
                    c = d[i][j-1]
                }
                t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, c))
                fill(d, i, j, c, d[i][j])
            }
        }

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                if d[i][j] == x {
                    continue
                }

                t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, x))
                fill(d, i, j, x, d[i][j])
            }
        }
        result = append(result, t)
    }

    best := math.MaxInt64
    for i := 0; i < K; i++ {
        best = min(best, len(result[i]))
    }

    bestIndex := -1
    for i := 0; i < K; i++ {
        if len(result[i]) == best {
            bestIndex = i
            break
        }
    }

    println(best)
    for i := 0; i < best; i++ {
        println(result[bestIndex][i])
    }
}

const (
    ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
    result := bufio.NewScanner(os.Stdin)
    result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
    result.Split(bufio.ScanWords)
    return result
}()

func readString() string {
    stdinScanner.Scan()
    return stdinScanner.Text()
}

func readInt() int {
    result, err := strconv.Atoi(readString())
    if err != nil {
        panic(err)
    }
    return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
    stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
    return fmt.Fprintln(stdoutWriter, args...)
}
  • [00:07] 上述のバグを直して提出し、49657497点をゲット. バグってなかったら2つ上がって238位だった.
package main

import (
    "bufio"
    "fmt"
    "math"
    "os"
    "strconv"
)

func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

func fill(d [][]byte, i, j int, x, y byte) {
    q := [][2]int{{i, j}}
    for len(q) != 0 {
        m, n := q[0][0], q[0][1]
        q = q[1:]
        d[m][n] = x
        if m > 0 {
            if d[m-1][n] == y {
                q = append(q, [2]int{m - 1, n})
            }
        }
        if m < N-1 {
            if d[m+1][n] == y {
                q = append(q, [2]int{m + 1, n})
            }
        }
        if n > 0 {
            if d[m][n-1] == y {
                q = append(q, [2]int{m, n - 1})
            }
        }
        if n < N-1 {
            if d[m][n+1] == y {
                q = append(q, [2]int{m, n + 1})
            }
        }
    }
}

//
var (
    N int
)

func main() {
    defer flush()

    _ = readInt()
    N = readInt()
    K := readInt()

    S := make([]string, N)
    for i := 0; i < N; i++ {
        S[i] = readString()
    }

    d := make([][]byte, N)
    for i := 0; i < N; i++ {
        d[i] = make([]byte, N)
    }

    result := make([][]string, 0, K)
    for n := 1; n <= K; n++ {
        x := byte(n + '0')
        t := make([]string, 0, 10000)

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                d[i][j] = S[i][j]
            }
        }

        for i := 1; i < N-1; i++ {
            for j := 1; j < N-1; j++ {
                if d[i][j] == x {
                    continue
                }

                a := 0
                b := 0
                if d[i-1][j] != d[i][j] {
                    a++
                    if d[i-1][j] == d[i+1][j] {
                        a++
                    }
                    if d[i-1][j] == d[i][j+1] && d[i-1][j] != d[i-1][j+1] {
                        a++
                    }
                }
                if d[i][j-1] != d[i][j] {
                    b++
                    if d[i][j-1] == d[i+1][j] && d[i][j-1] != d[i+1][j-1] {
                        b++
                    }
                    if d[i][j-1] == d[i][j+1] {
                        b++
                    }
                }

                if a == 0 && b == 0 {
                    continue
                }

                var c byte
                if a >= b {
                    c = d[i-1][j]
                } else {
                    c = d[i][j-1]
                }
                t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, c))
                fill(d, i, j, c, d[i][j])
            }
        }

        for i := 0; i < N; i++ {
            for j := 0; j < N; j++ {
                if d[i][j] == x {
                    continue
                }

                t = append(t, fmt.Sprintf("%d %d %c", i+1, j+1, x))
                fill(d, i, j, x, d[i][j])
            }
        }
        result = append(result, t)
    }

    best := math.MaxInt64
    for i := 0; i < K; i++ {
        best = min(best, len(result[i]))
    }

    bestIndex := -1
    for i := 0; i < K; i++ {
        if len(result[i]) == best {
            bestIndex = i
            break
        }
    }

    println(best)
    for i := 0; i < best; i++ {
        println(result[bestIndex][i])
    }
}

const (
    ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
    result := bufio.NewScanner(os.Stdin)
    result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
    result.Split(bufio.ScanWords)
    return result
}()

func readString() string {
    stdinScanner.Scan()
    return stdinScanner.Text()
}

func readInt() int {
    result, err := strconv.Atoi(readString())
    if err != nil {
        panic(err)
    }
    return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
    stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
    return fmt.Fprintln(stdoutWriter, args...)
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む