LoginSignup
3
2

More than 5 years have passed since last update.

Kotlinで500文字プログラミングしようとして挫折した

Last updated at Posted at 2017-06-06

はじめに

Qiitaの新サービスQiitadonが500文字までの文章を入力できてコードブロック&マークダウンに対応してると聞いたもので、喜び勇んで現在勉強中のKotlinを使って何か投稿しようとしたのが8年前、ちがった8日前でした。
qiita01.png

仕事と家族団らんで時間がとれないなか、ようやくプログラミングしたコードですが、やはり500文字制限は厳しいですね。コメント外しても800文字強。Qiitadonには投稿できません。
もう挫折したので、コードをさらして次の糧にしたいと思います。文字数をおさえるため可読性が落ちてますが、ご容赦くださいませ。

Kotlinいいね!って処をコードのあとのほうでまとめますね。

コード

import java.awt.Point

fun readl(): Int {//123のどれかの文字を入力受け付けるよ
  var ax : String? = readLine();var a=-1
  if(ax!=null && ax.length==1) a = "123".indexOf(ax[0], 0, false)
  return a+1
}
fun Point.read(){//Pointクラスに拡張関数を追加するよ
  while(x<1){print("x?"); x=readl()}
  while(y<1){print("y?"); y=readl()}
}
fun main(args:Array<String>) {
  var p =0//プレイヤー 0 or 1
  var ban =0//3x3の盤
  val ptn= arrayOf(86016,1344,21,66576,16644,4161,65793,4368)//勝利判定パターン
  while(ban.toString(2).count{it.equals('1')}<9) {//盤が全部うまっていたらゲーム終了するよ
    println("["+p+" turn]")//どっちの番か表示しようね
    /* 盤の表示 */
    for(i in 8 downTo 0){//上位ビットから表示
      print(".ox"[(ban shr i*2 ) and 0b11])//盤を2bitずつシフトで移動して、該当箇所を表示 0b00="."/0b01="o"/0b11="x"
      if(i % 3 ==0) println()//3文字表示したら改行
    }
    val pnt=Point();pnt.read()//マークする座標を入力するよ
    val point=(0b1 shl (6*(3-pnt.y)) shl ((3-pnt.x)*2)) shl p//座標を盤に変換するよ
    if((ban and point== 0) && ((ban shr (1-p) )and (point shr p)==0)){//マークしようとした座標は空いてるよね
      ban = ban or point//空いていたら、盤上にマークするよ
      if(ptn.find{it and (ban shr p) == it}!=null) {println("" + p + " won!");break}//勝利判定するよ
      p= p xor 1//次の人どうぞ
    }
  }
  println("game end")//ループを抜けたってことはゲーム終了だ。お疲れ様。
}

解説

もうお分かりでしょう、このコードはかつてあわや世界大戦勃発かという事態を阻止した伝説のゲームTIC TAC TOEいわゆる三目並べを実装しています。
1マスを2bitsとして、Int型の碁盤上に二人のプレイヤーが交互にマーキングして行き、縦、横、斜めの3文字判定パターンに一致したら勝利という実装をしています。

実行例

[0 turn]
...
...
...
x?2
y?2
[1 turn]
...
.o.
...
x?
(略 3目並ぶかマスが埋まるまで続く)

Kotlinいいね!

折角なのでKotlinっていいね!となった処をまとめました。

拡張関数

Kotlinでは既存クラスに関数を追加することができます。今回はjava.awt.Pointに対してxとyに標準入力から入力した値を入れる拡張関数read()を追加しました。

import java.awt.Point
//略
fun Point.read(){//Pointクラスに拡張関数を追加するよ
  while(x<1){print("x?"); x=readl()}
  while(y<1){print("y?"); y=readl()}
}
fun main(args:Array<String>) {
//(略)
    val pnt=Point();pnt.read()//マークする座標を入力するよ
//(略)
}

NULL安全

Kotlinでは、nullが許容される変数とされない変数を区別しています。変数定義の際にnull許容型なのかわかりますので、その変数に対してnull対策を忘れることはないでしょう。というか対策しないとコンパイルが通りません。
今回、標準入力を取得するため使用したreadLine()はString?型を返却する関数なので、変数もString?で定義しています。型名称の後の"?"でnull許容型かどうかの印ですね。String?はnull許容型なので、その後はnullチェックしないとコンパイルでエラーとなります。

  var ax : String? = readLine();var a=-1
  if(ax!=null && ax.length==1) a = "123".indexOf(ax[0], 0, false)

演算子

Kotlinでもほかの言語同様に論理演算が可能です。

今回は盤のマーキングや判定にshr,shl,and,or,xorを使用しました。今回使用した演算子の記述例を以下にまとめました。

演算子 説明 記述例 演算後
shr 右シフト 0b10 shr 1 0b01
shl 左シフト 0b01 shl 1 0b10
or 論理和 0b1001 or 0b1010 0b1011
and 論理積 0b1001 and 0b1010 0b1000
xor 排他的論理和 0b1001 xor 0b1010 0b0011

infix記法を使うことで、0b10.shr(1)ではなく、0b10 shr 1と記述することができるのが特徴ですね。

ラムダ式

Kotlinはラムダ式が使えて、超便利です。今回は、文字列のcount関数にカウントする条件{it.equals('1')}をラムダ式で渡しています。

  while(ban.toString(2).count{it.equals('1')}<9) {//盤が全部うまっていたらゲーム終了するよ

抜粋したコードは9マスの盤面全部が埋まったらゲームのループから抜ける判定を行っている箇所です。

文字操作

今回のプログラムでは以下のような文字列操作を行っています。

      print(".ox"[(ban shr i*2 ) and 0b11])//盤を2bitずつシフトで移動して、該当箇所を表示 0b00="."/0b01="o"/0b10="x"

String型の要素は[]で配列のようにアクセスすることができます。
抜粋したコードは、盤上の表記をまとめた文字列".ox"から、ban変数に2bitsで記録されたマーク情報(0b00:なし、0b01:プレイヤー0、0b10:プレイヤー1)を索引として文字を取り出して表示しています。

おわりに

この記事では全然表現しきれていませんが、Kotlinはプログラミングしていると、ああこれ楽だ!を良く味わえる良い言語です。ぜひ皆さんも使ってみてください。

ではまた!

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2