paizaの練習問題を解く マップの判定・縦横 Go編

こんにちは、ナナオです。 前回に引き続き競プロを実施していきたいと思います。 今回の問題は以下です。 マップの判定・縦 | レベルアップ問題集 | プログラミング学習サイト【paizaラーニング】 実装 こちらも前回の実装を応用すればできますね。 package main import "fmt" func main(){ var h, w int fmt.Scan(&h, &w) s := make([]string, h) for i := 0; i < h; i++ { fmt.Scan(&s[i]) } isWall := func(x, y int) bool { if x < 0 || x >= w || y < 0 || y >= h { return true } return s[y][x] == '#' } for y := 0; y < h; y++ { for x := 0; x < w; x++ { if isWall(x, y - 1) && isWall(x, y + 1) && isWall(x - 1, y) && isWall(x + 1, y) { fmt.Println(y, x) } } } } めでたしめでたし。

2026年2月22日 · にあえん

paizaの練習問題を解く マップの判定・縦 Go編

こんにちは、ナナオです。 前回に引き続き競プロを実施していきたいと思います。 今回の問題は以下です。 マップの判定・縦 | レベルアップ問題集 | プログラミング学習サイト【paizaラーニング】 実装 前回の実装を応用すればできますね。 package main import "fmt" func main(){ var h, w int fmt.Scan(&h, &w) s := make([]string, h) for i := 0; i < h; i++ { fmt.Scan(&s[i]) } isWall := func(x, y int) bool { if y < 0 || y >= h { return true } return s[y][x] == '#' } for y := 0; y < h; y++ { for x := 0; x < w; x++ { if isWall(x, y - 1) && isWall(x, y + 1) { fmt.Println(y, x) } } } } 簡単に実装できました。

2026年2月21日 · にあえん

paizaの練習問題を解く マップの判定・横 Go編

こんにちは、ナナオです。 前回に引き続き競プロを実施していきたいと思います。 今回の問題は以下です。 マップの判定・横 | レベルアップ問題集 | プログラミング学習サイト【paizaラーニング】 実装 行った実装は以下の通りです。 package main import ( "fmt" "strings" ) func main(){ var h, w int fmt.Scan(&h, &w) s := make([][]string, h) for i := 0; i < h; i++ { var line string fmt.Scan(&line) s[i] = strings.Split(line, "") } for i := 0; i < h; i++ { for j := 0; j < w; j++ { if j == 0 { if s[i][j + 1] == "#" { fmt.Println(i, j) } } else if j == len(s[i]) - 1 { if s[i][j - 1] == "#" { fmt.Println(i, j) } } else if s[i][j - 1] == "#" && s[i][j + 1] == "#" { fmt.Println(i, j) } } } } ただ計算量がO(N^2)だったり、ifのネストが深かったりあまりスマートなコードとは言えません。 isWall関数を実装してもっとスマートにします。 package main import ( "fmt" ) func main(){ var h, w int fmt.Scan(&h, &w) s := make([]string, h) for i := 0; i < h; i++ { fmt.Scan(&s[i]) } isWall := func(r, c int) bool { if c < 0 || c >= w { return true } return s[r][c] == '#' } for i := 0; i < h; i++ { for j := 0; j < w; j++ { if isWall(i, j - 1) && isWall(i, j + 1) { fmt.Println(i, j) } } } } これでネストがそこまで深くなく、少し簡潔なコードになりました。 ...

2026年2月20日 · にあえん

paizaの練習問題を解く 盤面の情報変更 Go編

こんにちは、ナナオです。 前回に引き続き競プロを実施していきたいと思います。 今回の問題は以下です。 盤面の情報変更 | レベルアップ問題集 | プログラミング学習サイト【paizaラーニング】 問題 前回の問題で、盤面の変更を伴う場合の実装をしろというものですね。 入力は以下の通りです。 H W N S_0 ... S_(H-1) y_1 x_1 ... y_N x_N 私の実装は以下の通りです。 package main import ( "fmt" "bufio" "os" "strings" ) func main(){ var h, w, n int fmt.Scan(&h, &w, &n) sc := bufio.NewScanner(os.Stdin) s := make([][]string, h) for i := 0; i < h; i++ { sc.Scan() s[i] = strings.Split(sc.Text(), "") } for i := 0; i < n; i++ { var x, y int fmt.Scan(&x, &y) s[y][x] = "#" } for i := 0; i < h; i++ { fmt.Println(strings.Join(s[i], "")) } } これだとx, yの読み込みに失敗してしまうのと、入力はy_n x_nで入力されるので修正しました。 これにすることでだいぶコードがすっきりしましたね。 package main import ( "fmt" "strings" ) func main(){ var h, w, n int fmt.Scan(&h, &w, &n) s := make([][]string, h) for i := 0; i < h; i++ { var line string fmt.Scan(&line) s[i] = strings.Split(line, "") } for i := 0; i < n; i++ { var x, y int fmt.Scan(&y, &x) s[y][x] = "#" } for i := 0; i < h; i++ { fmt.Println(strings.Join(s[i], "")) } } テストケースもこれで全部通りました。 ...

2026年2月19日 · にあえん

paizaの練習問題を解く 盤面の情報取得 Go編

こんにちは、ナナオです。 せっかくGoのチュートリアルを終えたので、今度は実践編ということでpaizaの練習問題を解いていこうと思います。 今回はこちらの問題です。 盤面の情報取得 | レベルアップ問題集 | プログラミング学習サイト【paizaラーニング】 まず標準入力をどうするか 最初の問題にふさわしいというか、標準入力のやり方がまだよく分かっていないので助かります。 入力は以下のような形式です。 H W N S_0 ... S_(H-1) y_1 x_1 ... y_N x_N 最初の一行は割と簡単に取得できます。 var h, w, n int fmt.Scan(&h, &w, &n) その後の行については以下のサイトを参考に実装しました。 【備忘】Go 言語の標準入力の基本的なこと #初心者向け - Qiita sc := bufio.NewScanner(os.Stdin) s := make([][]string, h) for i := 0; i < h; i++ { sc.Scan() s[i] = strings.Split(sc.Text(), "") } うーん、まぁここはもっとスマートに出来そうな気がしますが、とりあえずこれで。。 実装 標準入力ができればあとは割と簡単に実装できます。 全体の実装は以下の通りです。 package main import ( "fmt" "bufio" "os" "strings" "strconv" ) func main(){ var h, w, n int fmt.Scan(&h, &w, &n) sc := bufio.NewScanner(os.Stdin) s := make([][]string, h) for i := 0; i < h; i++ { sc.Scan() s[i] = strings.Split(sc.Text(), "") } for i := 0; i < n; i++ { sc.Scan() inputs := strings.Split(sc.Text(), " ") y, _ := strconv.Atoi(inputs[0]) x, _ := strconv.Atoi(inputs[1]) fmt.Println(s[y][x]) } } str -> intの変換にstrconvを使わなきゃいけなかったりするあたりがちょっと面倒ですが、まぁ静的言語のありがたい部分でもあります。 ...

2026年2月18日 · にあえん

Goのセットアップとチュートリアル【4】

こんにちは、ナナオです。 前回の続きでチュートリアルをやっていこうと思います。 sync.Mutex データの複数書き込みに対応するための機能です。 Rustの場合Mutex<...>のような形で書かれますが、Goの場合は構造体の一プロパティとして定義するようです。 package main import ( "fmt" "sync" "time" ) // SafeCounter is safe to use concurrently. type SafeCounter struct { mu sync.Mutex v map[string]int } // Inc increments the counter for the given key. func (c *SafeCounter) Inc(key string) { c.mu.Lock() // Lock so only one goroutine at a time can access the map c.v. c.v[key]++ c.mu.Unlock() } // Value returns the current value of the counter for the given key. func (c *SafeCounter) Value(key string) int { c.mu.Lock() // Lock so only one goroutine at a time can access the map c.v. defer c.mu.Unlock() return c.v[key] } func main() { c := SafeCounter{v: make(map[string]int)} for i := 0; i < 1000; i++ { go c.Inc("somekey") } // 一秒待つ(ゴルーチンのループを待つ) // ちなみに実務ではこんなは書き方しない time.Sleep(time.Second) fmt.Println(c.Value("somekey")) } 理解のためにこれをチャンネルで書き換えたコードが以下の通りです。 ...

2026年2月17日 · にあえん

Goのセットアップとチュートリアル【3】

こんにちは、ナナオです。 前回の続きでチュートリアルをやっていこうと思います。 Goroutines goroutine(ゴルーチン)はGoのランタイムで管理される軽量なスレッドです。 複雑な記法は必要ありません。goキーワードを関数実行時の先頭に入れるだけです。 package main import ( "fmt" "time" ) func say(s string) { for i := 0; i < 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func main() { go say("world") say("hello") } Channels チャネル型(Channel)は、チャネルオペレータ(<-)を使って値の送受信を行うことができます。 これを使うことでゴルーチンの値を簡単に取得することができます。 package main import "fmt" func sum(s []int, c chan int) { sum := 0 for _, v := range s { sum += v } c <- sum // send sum to c } func main() { s := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c) x, y := <-c, <-c // receive from c fmt.Println(x, y, x+y) } selectステートメント selectステートメント、これ最初に見たときは一見意味が分かりませんでした。 ...

2026年2月15日 · にあえん

Goのセットアップとチュートリアル【2】

こんにちは、ナナオです。 前回の続きでチュートリアルをやっていこうと思います。 map package main import "fmt" func main() { // このmapはnilのため、make関数で初期化する必要がある var m map[string]int // make関数でmapを作成する m = make(map[string]int) // このマップは初期化済み m = map[string]int{ "A": 1, "B": 2, } // キーの追加 m["Answer"] = 42 fmt.Println("The value:", m["Answer"]) // キーの変更 m["Answer"] = 48 fmt.Println("The value:", m["Answer"]) // キーの削除 delete(m, "Answer") fmt.Println("The value:", m["Answer"]) // キーの取得と存在確認 v, ok := m["Answer"] fmt.Println("The value:", v, "Present?", ok) } 関数 関数も変数として定義することができますし、引数にもできます。 package main import ( "fmt" "math" ) func compute(fn func(float64, float64) float64) float64 { return fn(3, 4) } func main() { hypot := func(x, y float64) float64 { return math.Sqrt(x*x + y*y) } fmt.Println(hypot(5, 12)) fmt.Println(compute(hypot)) fmt.Println(compute(math.Pow)) } メソッド メソッドはレシーバ引数を実装することで可能です。 ...

2026年2月13日 · にあえん

Goのセットアップとチュートリアル【1】

こんにちは、ナナオです。 Goを触り始めるにあたり、どこで勉強するかなどをまとめます。 インストール インストールはmiseでやりました。 Home | mise-en-place mise use -g go どこで勉強したか(するか) GoにはA tour of Goという公式のチュートリアルが用意されているので、そこでやりました。 A Tour of Go ローカルからこのチュートリアルを実行したい場合は以下のコマンドを実行します。 go install golang.org/x/website/tour@latest $GOROOT/bin/tour 印象に残ったところ naked return 関数内の変数をそのまま返却する実装方法 ほかの言語にはない特徴的な記法ですね(実務で使うかどうかは置いといて) package main import "fmt" func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return } func main() { fmt.Println(split(17)) } whileはない goではfor文がwhileを兼任しています。 package main import ( "fmt" ) func main() { sum := 1 for sum < 1000 { sum += sum } fmt.Println(sum) } 更にrustでいうloop文もforで表現可能です。 ...

2026年2月12日 · にあえん

GoでgRPCをササッと実装してみる 1

こんにちは。ナナオです。 今回は触ろうと思って触ってなかったgRPCに入門してみようと思います。 gRPCとは? gRPCとは、GoogleがRPCを実現するために作った技術のことです。 詳細については以下のサイトがかなり細かく説明してくれています。 https://zenn.dev/hsaki/books/golang-grpc-starting gRPCサーバーを動かす まずはgRPCのリクエストとレスポンスを定義するためのprotoファイルを作成します。 適当なディレクトリを作成して、Goモジュールとして初期化しておきましょう。 mkdir go_grpc_playground && cd go_grpc_playground go mod init go_grpc_playground 次に、protoファイルを作成します。 (参考にしてるサイトをパクってるだけですが。。) // protoのバージョンの宣言 syntax = "proto3"; // protoファイルから自動生成させるGoのコードの置き先 option go_package = "pkg/grpc"; // packageの宣言 package myapp; // サービスの定義 service GreetingService { // サービスが持つメソッドの定義 rpc Hello (HelloRequest) returns (HelloResponse); } // 型の定義 message HelloRequest { string name = 1; } message HelloResponse { string message = 1; } 次にこのprotoファイルからgoファイルを作成するためのモジュールをインストールします。 brewがあれば以下のコマンドで一発インストールできます。 brew install protobuf インストールするとprotocというコマンドが使用可能になります。 続けて、必要なモジュールを依存関係に追加しておきます。 go get -u google.golang.org/grpc go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc さて、今のディレクトリはこうなっています。 ...

2024年11月17日 · にあえん