にあえん

主にバックエンド・インフラ周りをやってます。 あそびばはこちら -> ナナオのあそびば

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日 · にあえん

lastpass cliを活用したパスワード管理

こんにちは、ナナオです。 皆さんパスワード管理ソフトには何を使っていますか? 私はLastPassを使っています。 業務では1Passwordを使っているのですが、いつもCLIがあることを羨ましく思っていました。 なんとlastpassにもCLIがあるということを最近知ったので、今回は使ってみようと思います。 初期設定 brewでインストール可能です。 brew install lastpass-cli コマンドはlpassで使用できます。 まずはログインしましょう。 lpass login <ログインに使用しているメールアドレス> すると以下のようにマスターパスワードの入力を促されます。 ログインに成功すると以下のようなメッセージが出力されます。 Success: Logged in as <ログインに使用しているメールアドレス>. 主なコマンドオプションは以下の通りです。 Customer lpass login [–trust] [–plaintext-key [–force, -f]] USERNAME lpass logout [–force, -f] lpass show [–sync=auto|now|no] [–clip, -c] [–all|–username|–password|–url|–notes|–field=FIELD|–id|–name] {UNIQUENAME|UNIQUEID} lpass ls [–sync=auto|now|no] [GROUP] lpass edit [–sync=auto|now|no] [–non-interactive] {–name|–username|–password|–url|–notes|–field=FIELD} {NAME|UNIQUEID} lpass generate [–sync=auto|now|no] [–clip, -c] [–username=USERNAME] [–url=URL] [–no-symbols] {NAME|UNIQUEID} LENGTH lpass duplicate [–sync=auto|now|no] {UNIQUENAME|UNIQUEID} lpass rm [–sync=auto|now|no] {UNIQUENAME|UNIQUEID} lpass sync [–background, -b] 感想 1PasswordのようにCIと組み合わせるみたいなことはできなさそう? ...

2026年2月16日 · にあえん

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日 · にあえん

ヒグチアイのライブに行った

こんにちは、ナナオです。 ライブに行ってきました。 ヒグチアイというアーティストです。 圧巻でした。 ソロで活動しているアーティストなのですが、今回のライブではバンドで演奏していました。 ちなみに私が好きな曲はこの備忘録という曲と走馬灯という曲です。 有名な曲は進撃の巨人のOPに採用された悪魔の子ですね。 いい曲ばかりなので、ぜひ聞いてみてね。

2026年2月14日 · にあえん

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日 · にあえん