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

#**はじめに**
Qiitaの新サービス[Qiitadon](https://qiitadon.com)が500文字までの文章を入力できてコードブロック&マークダウンに対応してると聞いたもので、喜び勇んで現在勉強中のKotlinを使って何か投稿しようとしたのが8年前、ちがった8日前でした。
![qiita01.png](https://qiita-image-store.s3.amazonaws.com/0/106997/2683b6d9-951e-e422-fd1e-57764bec9586.png)


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

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

#**コード**
```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()を追加しました。

```kotlin
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チェックしないとコンパイルでエラーとなります。

```kotlin
  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')}`をラムダ式で渡しています。

```Kotlin
  while(ban.toString(2).count{it.equals('1')}<9) {//盤が全部うまっていたらゲーム終了するよ
```
抜粋したコードは9マスの盤面全部が埋まったらゲームのループから抜ける判定を行っている箇所です。

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

```Kotlin
      print(".ox"[(ban shr i*2 ) and 0b11])//盤を2bitずつシフトで移動して、該当箇所を表示　0b00="."/0b01="o"/0b10="x"
```
String型の要素は[]で配列のようにアクセスすることができます。
抜粋したコードは、盤上の表記をまとめた文字列".ox"から、ban変数に2bitsで記録されたマーク情報(0b00:なし、0b01:プレイヤー0、0b10:プレイヤー1)を索引として文字を取り出して表示しています。

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

ではまた！