2023/3/30追記:
本記事には古い内容が含まれています。現在のV言語を用いた新しい記事を投稿したので、最新の内容をお求めの方は以下のリンクからどうぞ。
最近何かと話題のV言語が6月22日にオープンソースで公開されたので、生まれたてのV言語君にはABSをやってもらいます。
V言語ホームページ https://vlang.io/
V言語GitHub https://github.com/vlang/v
ABS(AtCoder) https://atcoder.jp/contests/abs
AtCoderにV言語はないが?????????
V言語はC言語と密接に関わっていて、Cで使えるライブラリはほぼ使えたり、Cのソースコードを吐いたりしてくれます。この吐き出されたソースコードを貼っつけて実行します。50000byte365000byte(2021/7/1現在)とかになりますが、気にしたら負けです。
また、V言語は出力は優秀なんですが、標準入力は文字列しか取れません(2021/7/1現在)。ライブラリが整ったらそれを使ったソースコードに更新します。が、今は仕方がないのでCからscanfを引っ張ってきます。面倒くさい、-^^-まるでどこかのJavaScr
2019/11/9追記:V言語がAtCoderの言語アプデで入りそうなんですが、安定でない0.1.xで大丈夫なのか…?私的には0.2.xを待った方がいいと思われるが。
2021/7/1追記:0.2.x来てますが、文法もまだ揺れてるし0.3.x待ちですかね。まぁ大丈夫だとは思いますが。ライブラリも欲しいところ。
2023/3/27追記:Language UpdateでV言語が候補に上がっていてLanguage Test 202301でV言語を使うことができます。なお、この記事のコードは古いため現在のV言語ではコンパイルできない可能性があります。現在AtCoderで使えるV言語での解答例はこちらで確認できます。
入力
C言語のライブラリの関数はC.hoge
で書けます。stdio.hはもう入ってるのでincludeする必要はありません。
また、Cの文字列はbyteの配列ですが、V言語のstringとして扱うには文字列の長さを含んでラップする必要があります。
2021/7/1現在はもっといい方法としてV言語のbyteの配列の0番目のポインタをCに渡し、bytestrメソッドでstringに変換できます。
fn C.scanf(&char, ...voidptr) int
fn scan_int() int {
scanned := 0
C.scanf(c'%d', &scanned)
return scanned
}
fn scan_string(max int) string {
arr := []u8{len: max}
unsafe { C.scanf(c'%s', &arr[0]) }
return unsafe { tos_clone(&arr[0]) }
}
解答
0問目 PracticeA - はじめてのあっとこーだー(Welcome to AtCoder)
fn main() {
num := scan_int() + scan_int() + scan_int()
hoge := scan_string(100)
println('$num $hoge')
}
入出力を問われている問題です。
変数の宣言には:=
を、代入には=
を用います。
V言語は文字列連結をしたり、文字列にリテラルを埋め込んだりできるので出力に関してはとても優秀です。
1問目 ABC086A - Product
fn main() {
a := scan_int()
b := scan_int()
println(if a*b%2 == 0 {'Even'} else {'Odd'})
}
簡単な数値演算です。
V言語のif文はRustやKotlinみたいな最近の言語らしく、三項演算子のように値を返すことができます。
2問目 ABC081A - Placing Marbles
fn main() {
mut ans := 0
m := scan_string(3)
one := `1`
for i in m {
if i == one {ans++}
}
println(ans)
}
簡単な文字列処理です。
1
のバイトコードの取得にはバッククォートを用います。
配列や文字列はfor...in構文が使えます。
3問目 ABC081B - Shift only
fn main() {
mut max := 1000000
n := scan_int()
for _ in 0..n {
mut hoge := scan_int()
mut num := 0
for {
if hoge%2 == 0 {
num++
hoge /= 2
} else {
break
}
}
if num < max {
max = num
}
}
println(max)
}
2で割れる回数を求めてその最小値を出します。
**「いくらfor...inが使いたいからってnum := iなんてする必要ないじゃない!」**ごめんなさい、書きたかった12!
使わない数値は、特殊な変数_
に放り込めばいいようになったようです。n回繰り返しにはこれを使えばよさげ
2019/11/9追記:for i in start..end
という構文が書けるようになったようです。[0].repeat(n)
とはおさらば
4問目 ABC087B - Coins
fn main() {
a := scan_int()
b := scan_int()
c := scan_int()
x := scan_int()
mut ans := 0
mut i := 0
mut j := 0
for i <= x/500 {
j = 0
for j <= (x-i*500)/100 {
k := x - i*500 - j*100
if a >= i && b >= j && c >= k/50 {
ans++
}
j++
}
i++
}
println(ans)
}
500円玉と100円玉の枚数で全探索をします。
for文はCのwhile文のように使うことができます(これが普通)。
5問目 ABC083B - Some Sums
fn main() {
n := scan_int()
a := scan_int()
b := scan_int()
mut ans := 0
for i := 1; i <= n; i++ {
istr := i.str()
mut sum := 0
for c in istr {
sum += int(c-`0`)
}
if a <= sum && sum <= b {
ans += i
}
}
println(ans)
}
1からnの数について、全ての桁を足します。
今回は数値を文字列に変換し、文字が表す数値を全て足しました。
Cのfor文みたいにもfor文を使うことができます。for文えらい万能やな
6問目 ABC088B - Card Game for Two
fn main() {
n := scan_int()
mut arr := []int{len: n, init: 0}
for i in 0..n {
arr[i] = scan_int()
}
arr.sort(a > b)
mut ans := 0
mut t := 1
for i in arr {
ans += t*i
t = -t
}
println(ans)
}
降順にクイックソートして足し引きをします。
クイックソートはarray
構造体に組み込まれているsort
関数を利用します。
sort
は特殊な関数です。a
とb
という特殊な変数が渡され、括弧内に式を書けばそれがソートの条件文として機能します。
7問目 ABC085B - Kagami Mochi
fn main() {
n := scan_int()
mut arr := [0].repeat(n)
for i in 0..n {
arr[i] = scan_int()
}
arr.sort()
mut ans := 1
mut t := arr[0]
for i in arr {
if i != t {
t = i
ans++
}
}
println(ans)
}
昇順にクイックソートして被りを抜いて数えます。
sort
関数の条件文を省略すると勝手に昇順になります。
8問目 ABC085C - Otoshidama
fn main() {
n := scan_int()
y := scan_int()
for i := 0; i <= n; i++ {
for j := 0; j <= n-i; j++ {
k := n-i-j
if i*1000 + j*5000 + k*10000 == y {
println('$k $j $i')
return
}
}
}
println('-1 -1 -1')
}
お札の枚数で全探索します。
テンプレ文字列は文明の利器。
9問目 ABC049C - 白昼夢 / Daydream
fn main() {
mut str := scan_string(100000)
if str.replace('eraser','').replace('erase','').replace('dreamer','').replace('dream','').len == 0 {
println('YES')
} else {
println('NO')
}
}
・・・
・・・・・・**嘘解法です!!**でもreplaceを連ねて書けるの、きもちいい。
10問目 ABC086C - Traveling
fn main() {
n := scan_int()
mut t := 0
mut x := 0
mut y := 0
for i in 0..n {
t0 := scan_int()
x0 := scan_int()
y0 := scan_int()
dt := t0-t
dx := x0-x
dy := y0-y
if dx+dy > dt || (dt-dx-dy)%2 == 1 {
println('No')
return
}
t = t0
x = x0
y = y0
}
println('Yes')
}
歩数が足りるかどうかと、往復で時間をつぶしてたどり着けるか(偶奇でわかる)を判定します。
完走した感想
まだEarly Access版なので足りない部分は存在したものの、これからたぶん伸びていく言語なのでそこはたぶん期待できます。簡単な構文で書けて速度も速い、これは今後次第で競プロにピッタリな言語になりえるのではないでしょうか。
更新履歴
2019/7/4 いつの間にか文字のバイト値を取得する構文ができてたのでバッククォートに変更
2019/9/25 stringとかrepeatとかアンダーバーとか他にも色々更新が入ってたので更新
2019/11/9 for i in start..end
を追加。end
はi
に含まれないのでいつものfor文の感覚で使える。
2021/7/1 0.2.xも出てるし重い腰を上げて更新するかとなったので。配列やunsafeなとこ周りが結構変わってます。