♬《148》憧れの背中
♬ 憧れの背中
勝利の喜びはない
いつか君に 追いつきたい
その背中 消えたら
グランドに 倒れて
汗にまみれて
起き上がれない
慰めの言葉もなく
やっと君を 追い越しても
その背中 褪せない
差し出した その手を
握り返して
夕陽にかざす
風に戦いでる プラタナスの影
今はもう 遠い街 同じ空
名前を呼ばれ…
託された夢は 果たせず
もしも君が 見ていたなら
僕の背を 目指して
走り出した 誰かが
旧いアルバム
時を運んだ
-
- 148#2017-04e:憧れの背中
Scala.use(better)《tips433》Hexothello
App15Window.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- import swing._ object App15Window extends MainFrame { val version = App15Window .getClass.getName+": #1.0.02 J" // ---------------------------------------- title = "15 puzzle" contents = new App15View(new Dimension(200,200)) peer.setLocationRelativeTo(null) } // ---------------------------------------- class App15View(size: Dimension) extends FlowPanel { preferredSize = size new Publisher { import swing.event.MouseClicked reactions += { case MouseClicked(_,point,_,_,_) => update(point) } }.listenTo(mouse.clicks) import scala.collection.mutable.ArrayBuffer val tiles = ArrayBuffer.empty[Tile] 0 to 14 foreach { i => tiles += Tile(i%4, i/4, i+1) } val nullTile = NullTile(3,3) tiles += nullTile shuffle(100) // ---------------------------------------- import java.awt.Point def update(point: Point) = detect(point) match { case Some(tile: Tile) => move(tile); repaint case None => } def detect(point: Point) = { tiles find { _.contains(point) } match { case Some(tile) => ;print(tile) if (tile.isInContactWith(nullTile)) Some(tile) else None case None => } } override def paintComponent(g: Graphics2D) = tiles foreach { _.paint(g) } def shuffle(count: Int) { val random = new scala.util.Random() 0 to count foreach { e => move(tiles(random.nextInt(15))) } } def move(tile: Tile) = tile.swap(nullTile) }
Apple.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. * ---------------------------------------- $ scalac -encoding "SJIS" -d bin src/{Apple,AppWindow,App15Window,Shape,Game}.scala $ date; scala -cp bin cherry.pie.application * ---------------------------------------- 2013年 10月27日 日曜日 12時42分32秒 JST ---------------------------------------- cherry.pie.application$: #1.0.03 cherry.pie.appWindow$: #1.0.03 cherry.pie.Shape$: #1.0.03 cherry.pie.Game$: #1.0.03 ---------------------------------------- (13,14) (58,14) -> (3,0) (43,40) -> (2,3) (29,66) -> (1,6) (15,96) -> (0,9) $ */ package cherry.pie // ---------------------------------------- import swing._ object application extends SimpleSwingApplication { val version = application .getClass.getName+": #1.0.03" // ---------------------------------------- println("-"*40) println(application.version) println(appWindow.version) println(Shape.version) println(Game.version) println("-"*40) def top = appWindow // ---------------------------------------- App15Window.visible = true }
AppWindow.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- import swing._ object appWindow extends MainFrame { val version = appWindow .getClass.getName+": #1.0.03" // ---------------------------------------- title = "Honeycomb" contents = new View(new Dimension(270,242)) peer.setLocationRelativeTo(null) } // ---------------------------------------- class View(size: Dimension) extends FlowPanel { preferredSize = size new Publisher { import swing.event.MouseClicked reactions += { case MouseClicked(_,p,_,_,_) => update(p) } }.listenTo(mouse.clicks) // ---------------------------------------- val tiles = createTiles def createTiles = { import scala.collection.mutable.ArrayBuffer val res = ArrayBuffer.empty[Honeycomb] 3 to 13 by 2 foreach { e => res += Honeycomb(e,0) res += Honeycomb(e,24) } 2 to 14 by 2 foreach { e => res += Honeycomb(e,3) res += Honeycomb(e,21) } 1 to 15 by 2 foreach { e => res += Honeycomb(e,6) res += Honeycomb(e,12) res += Honeycomb(e,18) } 0 to 16 by 2 foreach { e => res += Honeycomb(e,9) res += Honeycomb(e,15) } res.toArray } // ---------------------------------------- import java.awt.Point def update(point: Point) = { ;print("(%d,%d)" format (point.x, point.y)) tiles find { _.contains(point) } match { case Some(tile) => ;print(" -> "+tile) case None => } ;println } // ---------------------------------------- override def paintComponent(g: Graphics2D) = tiles foreach { _.paint(g) } }
Game.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- object Game { val version = Game .getClass.getName+": #1.0.03" } // ---------------------------------------- import java.awt._ object NullTile { def apply(x0: Int, y0: Int) = new Tile(x0, y0, 0) { override def paint(g: Graphics2D) = Rectangle(x*width, y*height, width, height) .paint(g, Color.lightGray) } } object Tile { def apply(x: Int, y: Int, n: Int) = new Tile(x, y, n) } class Tile(var x0: Int, var y0: Int, n: Int) { def x = x0 def x_=(x: Int) { x0 = x } def y = y0 def y_=(y: Int) { y0 = y } override def toString = "(%d,%d)%d" format (x,y,n) val (width, height) = (50, 50) val (px, py) = (x*width, y*height) val rect = Rectangle(px, py, width, height) val (dx, dy) = (4, 15) val symb = Symbol(n+"", px+dx, py+dy) def paint(g: Graphics2D) = { rect.paint(g) symb.paint(g) } def contains(p: Point) = rect.contains(p) def isInContactWith(that: Tile) = { val a = x - that.x val b = y - that.y a*a + b*b == 1 } def swap(that: Tile) = { val (this_x, this_y) = (x, y) this.move(that.x, that.y) that.move(this_x, this_y) } def move(x: Int, y: Int) { this.x = x; this.y = y val (px, py) = (x*width, y*height) rect.move(px, py) symb.move(px+dx, py+dy) } } // ---------------------------------------- object Honeycomb { def apply(x: Int, y: Int) = new Honeycomb(x, y) } class Honeycomb(x0: Int, y0: Int) { override def toString = "(%d,%d)" format (x0,y0) val hex = Hexagon(x0, y0) def contains(p: Point) = hex.contains(p) def paint(g: Graphics2D) = hex.paint(g, Color.green) }
Shape.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- object Shape { val version = Shape .getClass.getName+": #1.0.03" } // ---------------------------------------- import java.awt._ trait Shape { def paint(g: Graphics2D) def contains(p: Point): Boolean def move(x: Int, y: Int) } // ---------------------------------------- abstract class Geometry extends Shape { def paint(g: Graphics2D, fillColor: Color) def paint(g: Graphics2D): Unit = paint(g, defaultFillColor) def defaultFillColor = Color.white def drawColor = Color.black } // ---------------------------------------- object Hexagon { def apply(x: Int, y: Int) = new Hexagon(x, y) } class Hexagon(var x0: Int, var y0: Int) extends Geometry { import scala.collection.immutable.List var vertices = List( (1,0),(2,1),(2,3),(1,4),(0,3),(0,1) ) val (dx,dy) = (7,4) val scale = 2 def xPoints_(scale: Int) = points(scale) map { case (x,y) => x } def yPoints_(scale: Int) = points(scale) map { case (x,y) => y } def points(scale: Int) = { import scala.collection.mutable.ListBuffer val buf = new ListBuffer[(Int,Int)] vertices foreach { case (x,y) => val px = (x0+x)*dx*scale + x0 val py = (y0+y)*dy*scale + y0 - y0/3 buf += ( (px, py) ) } buf.toArray } def paint(g: Graphics2D, fillColor: Color) { val xPoints = xPoints_(scale) val yPoints = yPoints_(scale) val nPoints = vertices.length g.setColor(fillColor) g.fillPolygon(xPoints, yPoints, nPoints) g.setColor(drawColor) g.drawPolygon(xPoints, yPoints, nPoints) } def contains(p: Point) = { val (x,y) = (1,2) val px = (x0+x)*dx*scale + x0 val py = (y0+y)*dy*scale + y0 - y0/3 val x1 = px - p.x val y1 = py - p.y val xs = dx*scale x1*x1 + y1*y1 <= xs*xs } def move(x: Int, y: Int) = {} } // ---------------------------------------- object Rectangle { def apply(x: Int, y: Int, width: Int, height: Int) = (new Rectangle)(x, y, width, height) } class Rectangle extends Geometry { var peer: java.awt.Rectangle = _ def apply(x: Int, y: Int, width: Int, height: Int) = { peer = new java.awt.Rectangle(x, y, width, height); this } def paint(g: Graphics2D, fillColor: Color) { val (x, y) = (peer.x, peer.y) val (width, height) = (peer.width, peer.height) g.setColor(fillColor) g.fillRect(x, y, width, height) g.setColor(drawColor) g.drawRect(x, y, width, height) } def contains(p: Point) = peer.contains(p) def move(x: Int, y: Int) = peer.setLocation(x,y) } // ---------------------------------------- object Symbol { def apply(s: String, x: Int, y: Int) = new Symbol(s, x, y) } class Symbol(s: String, var x: Int, var y: Int) extends Geometry { def paint(g: Graphics2D, fillColor: Color) { g.setColor(drawColor) g.drawString(s, x, y) } def contains(p: Point) = false def move(x: Int, y: Int) = { this.x = x; this.y = y } } /* ---------------------------------------- src/Shape.scala:31: error: object List is not a value val vertices = List(3,4) ^ // ---------------------------------------- */
Java.use(better, Scala); S4(E3) 15パズル
#Scalaの栞
◉ Java.use(better, Scala); Season4(Episode1) 15パズル
変数を介して値を設定する
ときに、res3 とは何でしょうか。そこで、型を確認すると、
scala> :type res3 scala.swing.MainFrame
その変数を束縛している対象は、ウインドー MainFrame だと分ります。res3 は、隠れたウインドーを参照するための、隠れた変数です。というのも、対話形式では、実行した結果を後で参照できるように、隠れた変数が順に(res0, res1, ...)用意されるからです。
隠れた変数 res3 は、ウインドーに束縛されます。それなら、res3 を介して値を設定すると、隠れたウインドーが見えるようになるはずです。そこで、
scala> res3.visible = true
変数 res3 を介して、ウインドーの属性 visible に値 true を設定すると、ウインドーが現れます。このときの値 true は、真を表わす論理値です。同様に、
scala> res3.title = "A"
変数 res3 を介して、ウインドーの属性 title に値 "A" を設定すると、それがウインドーのタイトルに表示されます。二重引用符で囲まれた "A" は、文字列を表わします。すると、タイトルが違うのでウインドーを区別できます。
一般に、属性に値を設定(属性値を変更)するときには、次の書式に従います。
scala> オブジェクト.属性 = 値
この二重引用符には意味があります。というのも、それがないと、変数やモジュールなどと解釈されるからです。それを二重引用符で括ると「文字の並び」をそのまま解釈して欲しいという利用者の意図が、コンピューターに伝わります。
文字列のように、変数を介する必要がない、オブジェクトそのものを表現したものをリテラル〔literal〕と呼びます。そして、意味のあるオブジェクトはどれも、リテラルに帰着します。
変数を介して値を獲得する
変数を入力すると、その値が出力されます。これは、変数を評価したときに、その変数が束縛されている対象(オブジェクト)が得られるからです。
ときに、変数 res3 の値(型ではなく)は何でしょうか。変数 res3 を評価すると、その変数が束縛されているウインドーが得られます。そして、入力した変数を評価した結果として、得られたウインドーの情報が出力されます。このとき、
scala> res3 res4: scala.swing.MainFrame = scala.swing.Frame$$anon$1[frame2,0,22,128x37,layout=java.awt.BorderLayout,title=A,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,22,128x15,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=449,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]
変数 res3 を評価した結果を参照するために、また新たな変数 res4 が用意されます。res4 で始まる出力から、設定されたタイトル title=A を確認できます。このとき、2つの変数 res3 および res4 はどちらも、同じウインドーに束縛されます。それが事実なら、
scala> res4.title = "C"
変数 res3 に代えて、変数 res4 を介しても、タイトルを変更できるはずです。変数 res4 に代えて、変数 res3 を介して、その属性値を確認すると、
scala> res3.title res5: String = C 20131210031803
文字列 "C" が得られます。ここでも、その結果を参照するために、また新たな変数 res5 が用意されます。このとき、単純な文字列と複雑なウインドーとの間に、本質的な違いはありません。どちらも一人前のオブジェクトです。
変数 res5 res0 --------------------------------------------------- 型 String scala.swing.MainFrame 値 C scala.swing.Frame$$anon$1[frame0,...]
一般に、属性の値を獲得(属性値を参照)するときには、次の書式に従います。
scala> オブジェクト.属性
変数: 型 = 値
変数 res5 の型は文字列 String で、その値は文字列 C です。また、2つの変数 res3 および res4 がどちらも、同じウインドーに束縛される事実は、
scala> res3 == res4 res6: Boolean = true
でも確認できます。ここでも、また新たな変数 res6 が用意され、その型は論理型 Boolean で、その値は真を表わす true だと分ります。文字列と同様に、true もリテラルのひとつで、すでに何度も登場しています。
Created: 2012/12/18|Last updated: 2013/12/10 16:13:34
Scala.use(better)《tips432》Hexothello
App15Window.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- import swing._ object App15Window extends MainFrame { val version = App15Window .getClass.getName+": #1.0.02 J" // ---------------------------------------- title = "15 puzzle" contents = new App15View(new Dimension(200,200)) peer.setLocationRelativeTo(null) } // ---------------------------------------- class App15View(size: Dimension) extends FlowPanel { preferredSize = size new Publisher { import swing.event.MouseClicked reactions += { case MouseClicked(_,point,_,_,_) => update(point) } }.listenTo(mouse.clicks) import scala.collection.mutable.ArrayBuffer val tiles = ArrayBuffer.empty[Tile] 0 to 14 foreach { i => tiles += Tile(i%4, i/4, i+1) } val nullTile = NullTile(3,3) tiles += nullTile shuffle(100) // ---------------------------------------- import java.awt.Point def update(point: Point) = detect(point) match { case Some(tile: Tile) => move(tile); repaint case None => } def detect(point: Point) = { tiles find { _.contains(point) } match { case Some(tile) => ;print(tile) if (tile.isInContactWith(nullTile)) Some(tile) else None case None => } } override def paintComponent(g: Graphics2D) = tiles foreach { _.paint(g) } def shuffle(count: Int) { val random = new scala.util.Random() 0 to count foreach { e => move(tiles(random.nextInt(15))) } } def move(tile: Tile) = tile.swap(nullTile) }
Apple.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. * ---------------------------------------- $ scalac -encoding "SJIS" -d bin src/{Apple,AppWindow,App15Window,Shape,Game}.scala $ date; scala -cp bin cherry.pie.application * ---------------------------------------- 2013年 11月13日 水曜日 17時58分00秒 JST ---------------------------------------- cherry.pie.application$: #1.0.03 cherry.pie.appWindow$: #1.0.03 cherry.pie.Shape$: #1.0.03 cherry.pie.Game$: #1.0.03 ---------------------------------------- (16,16) -> (0,0) (45,16) -> (2,0) (74,17) -> (4,0) (31,41) -> (1,3) (57,40) (45,68) -> (2,6) $ */ package cherry.pie // ---------------------------------------- import swing._ object <span style="color: #ff5252">application</span> extends SimpleSwingApplication { val version = application .getClass.getName+": #1.0.03" // ---------------------------------------- println("-"*40) println(application.version) println(appWindow.version) println(Shape.version) println(Game.version) println("-"*40) def top = appWindow // ---------------------------------------- App15Window.visible = true }
AppWindow.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- import swing._ object appWindow extends MainFrame { val version = appWindow .getClass.getName+": #1.0.03" // ---------------------------------------- title = "Honeycomb" contents = new View(new Dimension(200,200)) peer.setLocationRelativeTo(null) } // ---------------------------------------- class View(size: Dimension) extends FlowPanel { preferredSize = size new Publisher { import swing.event.MouseClicked reactions += { case MouseClicked(_,p,_,_,_) => update(p) } }.listenTo(mouse.clicks) // ---------------------------------------- import scala.collection.mutable.ArrayBuffer val tiles = ArrayBuffer.empty[Honeycomb] tiles += Honeycomb(0,0) tiles += Honeycomb(2,0) tiles += Honeycomb(4,0) tiles += Honeycomb(1,3) tiles += Honeycomb(2,6) // ---------------------------------------- import java.awt.Point def update(point: Point) { ;print("(%d,%d)" format (point.x, point.y)) tiles find { _.contains(point) } match { case Some(tile) => ;print(" -> "+tile) case None => } ;println } // ---------------------------------------- override def paintComponent(g: Graphics2D) = tiles foreach { _.paint(g) } }
Game.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- object Game { val version = Game .getClass.getName+": #1.0.03" } // ---------------------------------------- import java.awt._ object NullTile { def apply(x0: Int, y0: Int) = new Tile(x0, y0, 0) { override def paint(g: Graphics2D) = Rectangle(x*width, y*height, width, height) .paint(g, Color.lightGray) } } object Tile { def apply(x: Int, y: Int, n: Int) = new Tile(x, y, n) } class Tile(var x0: Int, var y0: Int, n: Int) { def x = x0 def x_=(x: Int) { x0 = x } def y = y0 def y_=(y: Int) { y0 = y } override def toString = "(%d,%d)%d" format (x,y,n) val (width, height) = (50, 50) val (px, py) = (x*width, y*height) val rect = Rectangle(px, py, width, height) val (dx, dy) = (4, 15) val symb = Symbol(n+"", px+dx, py+dy) def paint(g: Graphics2D) { rect.paint(g) symb.paint(g) } def contains(p: Point) = rect.contains(p) def isInContactWith(that: Tile) = { val a = x - that.x val b = y - that.y a*a + b*b == 1 } def swap(that: Tile) = { val (this_x, this_y) = (x, y) this.move(that.x, that.y) that.move(this_x, this_y) } def move(x: Int, y: Int) { this.x = x; this.y = y val (px, py) = (x*width, y*height) rect.move(px, py) symb.move(px+dx, py+dy) } } // ---------------------------------------- object Honeycomb { def apply(x: Int, y: Int) = new Honeycomb(x, y) } class Honeycomb(x0: Int, y0: Int) { override def toString = "(%d,%d)" format (x0,y0) val peer = Hexagon(x0, y0) def contains(p: Point) = peer.contains(p) def paint(g: Graphics2D) = peer.paint(g, Color.green) }
Shape.scala
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- object Shape { val version = Shape .getClass.getName+": #1.0.03" } // ---------------------------------------- import java.awt._ trait Shape { def paint(g: Graphics2D) def contains(p: Point): Boolean def move(x: Int, y: Int) {} } // ---------------------------------------- abstract class Geometry extends Shape { def paint(g: Graphics2D, fillColor: Color) def paint(g: Graphics2D): Unit = paint(g, defaultFillColor) def defaultFillColor = Color.white def defaultDrawColor = Color.black } // ---------------------------------------- object Hexagon { def apply(x: Int, y: Int) = new Hexagon(x, y) } class Hexagon(var x0: Int, var y0: Int) extends Geometry { val (dx,dy,scale) = (7,4,2) import scala.collection.immutable.List val vertices = List*1 def nPoints = vertices.length val bounds = points(scale) def xPoints = bounds map { case (x,_) => x } def yPoints = bounds map { case (_,y) => y } def points(scale: Int) = { import scala.collection.mutable.ListBuffer val buf = ListBuffer.empty[(Int,Int)] vertices foreach { case (x,y) => val px = (x0+x)*dx*scale + x0 val py = (y0+y)*dy*scale + y0 - y0/3 buf += *2 } buf.toArray } // ---------------------------------------- def paint(g: Graphics2D, fillColor: Color) { g.setColor(fillColor) g.fillPolygon(xPoints, yPoints, nPoints) g.setColor(defaultDrawColor) g.drawPolygon(xPoints, yPoints, nPoints) } def contains(p: Point) = { val (x,y) = (1,2) val px = (x0+x)*dx*scale + x0 val py = (y0+y)*dy*scale + y0 - y0/3 val x1 = px - p.x val y1 = py - p.y val xs = dx*scale x1*x1 + y1*y1 <= xs*xs } } // ---------------------------------------- object Rectangle { def apply(x: Int, y: Int, width: Int, height: Int) = (new Rectangle)(x, y, width, height) } class Rectangle extends Geometry { var peer: java.awt.Rectangle = _ def apply(x: Int, y: Int, width: Int, height: Int) = { peer = new java.awt.Rectangle(x, y, width, height); this } def paint(g: Graphics2D, fillColor: Color) { val (x, y) = (peer.x, peer.y) val (width, height) = (peer.width, peer.height) g.setColor(fillColor) g.fillRect(x, y, width, height) g.setColor(defaultDrawColor) g.drawRect(x, y, width, height) } def contains(p: Point) = peer.contains(p) override def move(x: Int, y: Int) = peer.setLocation(x,y) } // ---------------------------------------- object Symbol { def apply(s: String, x: Int, y: Int) = new Symbol(s, x, y) } class Symbol(s: String, var x: Int, var y: Int) extends Geometry { def paint(g: Graphics2D, fillColor: Color) { g.setColor(defaultDrawColor) g.drawString(s, x, y) } def contains(p: Point) = false override def move(x: Int, y: Int) = { this.x = x; this.y = y } } /* src/Shape.scala:31: error: object List is not a value val vertices = List(3,4) ^/
Scala.use(better)《tips431》Hexothello
》App15Window.scala《
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- import swing._ object App15Window extends MainFrame { val version = App15Window .getClass.getName+": #1.0.03" // ---------------------------------------- title = "15 puzzle" contents = new App15View(new Dimension(200,200)) peer.setLocationRelativeTo(null) } // ---------------------------------------- class App15View(size: Dimension) extends FlowPanel { preferredSize = size new Publisher { import swing.event.MouseClicked reactions += { case MouseClicked(_,point,_,_,_) => update(point) } }.listenTo(mouse.clicks) import scala.collection.mutable.ArrayBuffer val tiles = ArrayBuffer.empty[Tile] 0 to 14 foreach { i => tiles += Tile(i%4, i/4, i+1) } val nullTile = NullTile(3,3) tiles += nullTile shuffle(100) // ---------------------------------------- import java.awt.Point def update(point: Point) = detect(point) match { case Some(tile: Tile) => move(tile); repaint case None => } def detect(point: Point) = { tiles find { _.contains(point) } match { case Some(tile) => ;print(tile) if (tile.isInContactWith(nullTile)) Some(tile) else None case None => } } override def paintComponent(g: Graphics2D) = tiles foreach { _.paint(g) } def shuffle(count: Int) { val random = new scala.util.Random() 0 to count foreach { e => move(tiles(random.nextInt(15))) } } def move(tile: Tile) = tile.swap(nullTile) }
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. * ---------------------------------------- $ scalac -encoding "SJIS" -d bin src/{Apple,AppWindow,App15Window,Shape,Game}.scala $ date; scala -cp bin cherry.pie.application * ---------------------------------------- 2013年 11月 1日 金曜日 00時10分03秒 JST ---------------------------------------- cherry.pie.application$: #1.0.03 cherry.pie.appWindow$: #1.0.03 cherry.pie.Shape$: #1.0.03 cherry.pie.Game$: #1.0.03 ---------------------------------------- (1,1)4(2,1)5(2,2)7(2,3)1(3,3)13(3,2)12(3,1)3(3,0)11(2,0)10(2,1)7(2,2)1(3,2)3(3,1)11(3,0)10(2,0)7(1,0)4(0,0)2(0,1)8(0,2)6(1,2)9(2,2)3(3,2)11(3,1)10(3,0)7(2,0)4(1,0)2(0,0)8(1,0)8(1,1)5(1,2)3(2,2)11(1,2)11(0,2)9(0,1)6(0,1)0(0,0)8(1,0)5(2,0)2(2,1)1(1,1)3(0,1)8(1,1)8(1,0)2(2,0)1(2,1)3(1,1)2(0,1)8(0,0)5(1,0)1(1,1)8(2,1)2(2,1)0(3,1)7(3,0)4(2,0)3(1,0)8(1,1)2(2,1)7(2,0)8(3,0)3(3,1)4(2,1)8(1,1)7(1,2)9(2,2)11(2,2)0(3,2)10(3,1)8(2,1)7(1,1)9(1,2)11(1,2)0(0,2)6(0,1)5(1,1)11(1,2)6(2,2)10(2,1)9(1,1)6(0,1)11(0,2)5(1,2)10(1,1)11(2,1)6(3,1)7(3,2)8(3,3)12(2,3)13(1,3)15(0,3)14(0,2)10(1,2)11(2,2)9(2,3)15(1,3)14(0,3)10(0,2)11(1,2)9(1,3)10(0,3)11(0,2)9(1,2)10(1,3)11(2,3)14(3,3)13(2,3)13(2,2)15(3,2)12(2,2)12(0,2)10(1,2)11(0,2)10(0,3)9(1,3)14(2,3)15(2,3)0(3,3)13$ */ package cherry.pie // ---------------------------------------- import swing._ object <span style="color: #ff5252">application</span> extends SimpleSwingApplication { val version = application .getClass.getName+": #1.0.03" // ---------------------------------------- println("-"*40) println(application.version) println(appWindow.version) println(Shape.version) println(Game.version) println("-"*40) def top = appWindow // ---------------------------------------- App15Window.visible = true }
》AppWindow.scala《
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- import swing._ object appWindow extends MainFrame { val version = appWindow .getClass.getName+": #1.0.03" // ---------------------------------------- title = "Honeycomb" contents = new View(new Dimension(250,250)) peer.setLocationRelativeTo(null) } // ---------------------------------------- class View(size: Dimension) extends FlowPanel { preferredSize = size new Publisher { import swing.event.MouseClicked reactions += { case MouseClicked(_,p,_,_,_) => update(p) } }.listenTo(mouse.clicks) // ---------------------------------------- val nullTile = NullTile(3,3) import scala.collection.mutable.ArrayBuffer val tiles = ArrayBuffer.empty[Tile] 0 to 14 foreach { i => tiles += Tile(i%4, i/4, i+1) } tiles += nullTile shuffle(100) // ---------------------------------------- import java.awt.Point def update(point: Point) = detect(point) match { case Some(tile: Tile) => move(tile); repaint case None => } def detect(point: Point) = { tiles find { _.contains(point) } match { case Some(tile) => ;print(tile) if (tile.isInContactWith(nullTile)) Some(tile) else None case None => } } def shuffle(count: Int) { val random = new scala.util.Random 0 to count foreach { _ => move(tiles(random.nextInt(15))) } } def move(tile: Tile) = tile.swap(nullTile) // ---------------------------------------- override def paintComponent(g: Graphics2D) = tiles foreach { _.paint(g) } }
》Game.scala《
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- object Game { val version = Game .getClass.getName+": #1.0.03" } // ---------------------------------------- import java.awt._ object NullTile { def apply(x0: Int, y0: Int) = new Tile(x0, y0, 0) { override def paint(g: Graphics2D) = Rectangle(x*width, y*height, width, height) .paint(g, Color.lightGray) } } object Tile { def apply(x: Int, y: Int, n: Int) = new Tile(x, y, n) } class Tile(var x0: Int, var y0: Int, n: Int) { def x = x0 def x_=(x: Int) { x0 = x } def y = y0 def y_=(y: Int) { y0 = y } override def toString = "(%d,%d)%d" format (x,y,n) val (width, height) = (50, 50) val (px, py) = (x*width, y*height) val rect = Rectangle(px, py, width, height) val (dx, dy) = (4, 15) val symb = Symbol(n+"", px+dx, py+dy) def paint(g: Graphics2D) { rect.paint(g) symb.paint(g) } def contains(p: Point) = rect.contains(p) def isInContactWith(that: Tile) = { val a = x - that.x val b = y - that.y a*a + b*b == 1 } def swap(that: Tile) = { val (this_x, this_y) = (x, y) this.move(that.x, that.y) that.move(this_x, this_y) } def move(x: Int, y: Int) { this.x = x; this.y = y val (px, py) = (x*width, y*height) rect.move(px, py) symb.move(px+dx, py+dy) } }
》Shape.scala《
/* * Copyright (c) 2010-2013, KOTSUBU-chan and/or its affiliates. * Copyright (c) 1998, Atelier-AYA. * All rights reserved. */ package cherry.pie // ---------------------------------------- object Shape { val version = Shape .getClass.getName+": #1.0.03,a" } // ---------------------------------------- import java.awt._ trait Shape { def paint(g: Graphics2D) def contains(p: Point): Boolean def move(x: Int, y: Int) } // ---------------------------------------- abstract class Geometry extends Shape { def paint(g: Graphics2D, fillColor: Color) def paint(g: Graphics2D): Unit = paint(g, defaultFillColor) def defaultFillColor = Color.white def defaultDrawColor = Color.black } // ---------------------------------------- object Rectangle { def apply(x: Int, y: Int, width: Int, height: Int) = (new Rectangle)(x, y, width, height) } class Rectangle extends Geometry { var peer: java.awt.Rectangle = _ def apply(x: Int, y: Int, width: Int, height: Int) = { peer = new java.awt.Rectangle(x, y, width, height); this } def paint(g: Graphics2D, fillColor: Color) { val (x, y) = (peer.x, peer.y) val (width, height) = (peer.width, peer.height) g.setColor(fillColor) g.fillRect(x, y, width, height) g.setColor(defaultDrawColor) g.drawRect(x, y, width, height) } def contains(p: Point) = peer.contains(p) def move(x: Int, y: Int) = peer.setLocation(x,y) } // ---------------------------------------- object Symbol { def apply(s: String, x: Int, y: Int) = new Symbol(s, x, y) } class Symbol(s: String, var x: Int, var y: Int) extends Geometry { def paint(g: Graphics2D, fillColor: Color) { g.setColor(defaultDrawColor) g.drawString(s, x, y) } def contains(p: Point) = false def move(x: Int, y: Int) = { this.x = x; this.y = y } }
Java.use(better, Scala); S4(E2) 15パズル
#Scalaの栞
◉ Java.use(better, Scala); Season4(Episode2) 15パズル
[:contents]
対話形式の意義
最初に、次のコードの断片を入力します。すると、
scala> new swing.MainFrame { visible = true } res0: scala.swing.MainFrame = scala.swing.Frame$$anon$1[frame0,0,22,128x37,layout=java.awt.BorderLayout,title=,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,22,128x15,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=449,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]
ディスプレーの左上隅にウインドーが現れ、その情報がターミナルに出力されます。そこで、res0 で始まる出力から、その詳細を読み取ります。
まず、正式には scala.swing.MainFrame で、scala. の部分は省略可能と分ります。次に、128x37 から、ウインドーの寸法(幅x高さ)が分ります。そして、128x15 から、タイトルの部分を除いたウインドーの高さが 15(かつ、タイトルの高さが 22=37-15)と分ります。他の情報は、後述します。
では、一部を省略して入力すると、どうなるでしょうか。すると、
scala> new swing.MainFrame res1: scala.swing.MainFrame = scala.swing.Frame$$anon$1[frame1,0,22,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,0,0x0,invalid,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=449,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]
ウインドーは表示されずに、res1: で始まる情報だけを出力します。ウインドーは寸法を持たない 0x0 なので、隠れて見えない hidden のが分ります。
対話形式では、利用者が「入力」したコードをコンピューターが解釈して、実行した結果に関する情報を「出力」します。つまり、入出力を介して、利用者とコンピューターが「対話」を繰り返しながら、試行錯誤によって経験を積みます。
サブコマンド :type
さらに省略すると、どうなるでしょうか。すると、
scala> new MainFrame:8: error: not found: type MainFrame new MainFrame ^
エラーメッセージを出力します。そこから原因を探ると、型 MainFrame を確認できないのが分ります。そこで、help にあったサブコマンド :type を利用して、その型を確認します。サブコマンドは、コロン「:」に続けて入力します。
scala> :type MainFrame Failed to determine type.
やはり、型を決定できません。そこで、swing. を明記すると、
scala> :type swing.MainFrame <notype>
今度は「型なし」です。そして、swing だけを確認すると、
scala> :type swing package swing
swing は、パッケージだと分ります。サブコマンド :type を利用すると、有効な型の情報が得られます。が、その型が無効なら、それこそ「形無し」です。
import
import を利用すると、正式な名前を省略できるので便利です。たとえば、
scala> import swing.MainFrame import swing.MainFrame
swing.MainFrame に代えて、これを省略した末尾の MainFrame だけで認識できます。実はこの swing.MainFrame も、scala.swing.MainFrame を省略したものです。すると、
scala> new MainFrame res3: scala.swing.MainFrame = scala.swing.Frame$$anon$1[frame2,0,22,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,0,0x0,invalid,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=449,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]
今度は、同じコードの断片を入力しても、エラーメッセージを出力しません。変わらずウインドーは現れませんが、実行した結果に関する情報を出力します。
Created: 2012/12/18|Last updated: 2013/12/10 16:12:06