見出し画像

AtCoderでGoをはじめてみる

はじめに

こんにちわ。LiKafです

月に一本継続してNoteを出していこうという取り組みの第一弾です
今回は備忘録を兼ねて『AtCoderを使ってGoをはじめてみた』記録を書いていきます

Goの基本的な文法とかが気になる方はぜひ読んでみてください。

AtCoderをよく知らない方は、
AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~とかを参考にしてください
(もしやったことないなら、やってみた方がいいと思います。異常に楽しいです、ガチで。)



なぜやろうと思ったか

なぜ無数にある言語の中からGoをやろうと思ったのかというと、答えは単純で、夏のインターンでGoを使って開発を行う機会を頂けたからです。

では、なぜAtCoderでGoの勉強をはじめようと思ったのかというと、これまでGoを読んだことも書いたこともない私にとって、最初から100行以上のコードを書くのはハードルが高すぎると考えたからです。

また、研究や他のアルバイトなどで時間的に余裕もないので、これまで慣れ親しんだAtCoderを用いて、低diff埋めと並行してGoの勉強をしたいなと考えました。

ほかにも、他の人の提出したコードを簡単に参照できる点もAtCoderを通じてプログラミング言語を学習する上で優れたところだと思います。


Go言語とは

GoのDocumentによると、

Goプログラミング言語は、プログラマーの生産性を高めるためのオープンソースプロジェクトである。

Goは、表現力が豊かで、簡潔で、クリーンで、効率的です。その並行性メカニズムにより、マルチコアやネットワーク化されたマシンを最大限に活用するプログラムを簡単に書くことができ、斬新な型システムにより、柔軟でモジュール化されたプログラムを構築することができます。Goはマシン・コードに素早くコンパイルでき、ガベージ・コレクションの利便性とランタイム・リフレクションのパワーを備えている。これは、動的型付けされたインタプリタ言語のように感じられる、高速な静的型付けコンパイル言語である。

DeepLで翻訳

と書かれていました
正直あまりピンと来ませんが、とりあえずGoogleが設計した言語ってことで凄いんだろなぁと思います(適当)


早速やってみる

ChatGPTを使う

本来はDocumentを参照するべきだとは思うのですが、今回はお手軽に必要最低限の知識で始めたかったので、ChatGPTを使用します。

とりあえず基本的な構造や、標準入力・標準出力・ループ・条件分岐の4つの文法を学びたかったので、良さげな問題をChatGPT(GPT-3.5)に解いてもらい、解説してもらうことにしました。

解いてもらった問題は、2023/07/29に行われた
ユニークビジョンプログラミングコンテスト2023 夏(ABC312)
A - Chordです。

https://atcoder.jp/contests/abc312/tasks/abc312_a

これを解いてもらうと以下のようなコードを提示されました。

package main

import "fmt"

func isValidPattern(S string) bool {
    patterns := []string{"ACE", "BDF", "CEG", "DFA", "EGB", "FAC", "GBD"}
    for _, pattern := range patterns {
        if S == pattern {
            return true
        }
    }
    return false
}

func main() {
    var S string
    fmt.Scan(&S)

    if isValidPattern(S) {
        fmt.Println("Yes")
    } else {
        fmt.Println("No")
    }
}

このコードの解説は以下です

スクショ

ふむふむ。

以下心の声

とりあえず、
コードの先頭には

package main

をつけて、
標準入出力には

import "fmt"

を import しないといけなくて、関数は

func 関数名(引数名 引数の型) 関数の返り値の型 {
}

ってするのか。

書かれてはないけど、

var S string

は、var で JavaScript みたいに変数であることを宣言して、
Sが変数名、その次にその型を書くことで
Sという名前のstring型の変数を宣言するのね。はいはい。

patterns := []string{"ACE", "BDF", "CEG", "DFA", "EGB", "FAC", "GBD"}

これは、

var patterns []string
patterns = {"ACE", "BDF", "CEG", "DFA", "EGB", "FAC", "GBD"}

の省略ね。

定数を宣言するときは

const Pi = 3.14159

こうするのね。

標準入力は

fmt.Scan(&S)

みたいにするのか。

標準出力は

fmt.Println("Yes")

こうするのね。
ちなみに、Printlnは引数それぞれにスペース開けてくれて、行末に改行してくれるらしい。他にもPrintとかPrintfとかあるから適宜良いやつ選べばOK

ループは

for i, value := range 配列名 {
}

ってすると i にindexが、value に要素が入るのか。
Pythonのenumerate関数と一緒だ。

for i := 0; i < N; i++ {
}

普通の整数 N までのループはこう書けるのか。

条件分岐は

if S == pattern {
}

みたいにするのか。

うん。Go、†完全に理解†した


実際に自力で解いてみる

Goを完全に理解()したところで実際にGoで問題を解いてみようと思います。

今回、栄えある一番最初のGoで解く問題として選ばれたのは、 AtCoder Beginner Contest 233A - 10yen Stamp です

https://atcoder.jp/contests/abc233/tasks/abc233_a

再度以下心の声

え〜っと、
まず

コードの先頭に付けないといけないものつけて、標準入出力したいから fmt を import する。

package main

import "fmt"

func main() {
    // ここになんか書く
}

で、まず、整数X, Yを標準入力から受け取りたい。
Goで整数の型はintだから、

package main

import "fmt"

func main() {
    var X int
    var Y int
    fmt.Scan(&X)
    fmt.Scan(&Y)
}

ってすればOK。

求める答えは、

Xに10を何回足すことで、Y以上になるか。

を求めれば良いので、
例えばX = 21, Y = 46
のとき、(21 + 10 + 10 + 10) = 51 >= 46 で、求める答えは3

より簡単に説明すると、

Y - Xを10で割った値について、小数点以下を切り上げたものが答え
ただし、YがX以下である場合は0

e.g.
(46-21)/10 = 2.5 なので、これを切り上げて3

となる。
以上から、

package main

import "fmt"

func main() {
    var X int
    var Y int
    fmt.Scan(&X)
    fmt.Scan(&Y)

    if Y <= X {
        fmt.Println(0)
        return
    }
    
    fmt.Println((Y-X+9)/10))
}

このようにすると解けることがわかる。

https://atcoder.jp/contests/abc233/submissions/44095579


感想

これまで一度も見たことも触ったこともない言語だったので嫌厭していたけれど、簡単な問題を解いてGoの基本文法を知れただけでも親近感を持つことができたので、いい経験だったと思います。

AtCoder ProblemsのLanguageも稼げるし、低diffも埋めれるし、Goの勉強にもなるし、一石三鳥なので今後もちょこちょこやっていきます。

最後まで読んでいただいてありがとうございました!
また来月の記事も読んでください!

https://kenkoooo.com/atcoder/#/user/LiKaf?userPageTab=Languages


おまけ

あと2問追加で解いてみました。

一問目

提出コード

package main
 
import "fmt"
 
func main() {
	var L, R int
	fmt.Scan(&L)
	fmt.Scan(&R)
	var S string
	fmt.Scan(&S)
 
	var ans string
	for i := 0; i < L - 1; i++ {
		ans += string(S[i])
	}
	for i := 0; i < R - L + 1; i++ {
		ans += string(S[R - 1 - i])
	}
	for i := R; i < len(S); i++ {
		ans += string(S[i])
	}
	fmt.Println(ans)
}

ループを使って文字列操作する


二問目

提出コード

package main
 
import (
	"fmt"
	"sort"
)
 
func main() {
	var S string
	fmt.Scan(&S)
 
	strings := []string{}
	for i := 0; i < len(S); i++ {
		var tmp string
		for j := 0; j < len(S); j++ {
			tmp += string(S[(i + j) % len(S)])
		}
		strings = append(strings, tmp)
	}
 
	sort.Strings(strings)
	fmt.Println(strings[0])
	fmt.Println(strings[len(strings) - 1])
}

Goの配列はCのように固定長なので、sliceというデータ構造を利用した
また、並び替えのために sort を import した


この記事が参加している募集

AIとやってみた

この記事が気に入ったらサポートをしてみませんか?