Language detail: Groovy

Coverage: 86.80%
number of '+' ratings
contribution for coverage

Unsolved challenges

codes

Feed

Used modules

next >>

inline/embeded bytecode assembly (Nested Flatten)

Groovyからバイトコードを操作するため、バイトコード生成のためのライブラリ「javassist」を使っています。ただ、残念なことにjavassistは抽象度が高すぎて、バイトコードの指定にJavaソースコードを使うこともできてしまいます。もちろんバイトコードインストラクションレベルでの指定もできるのですが、あえてするのも意味ないのでこのままで。

Groovyにとっては「インラインJava」ができる例として。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Grab('javassist:javassist:3.8.0.GA')
import javassist.*;

ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("DuffsDevice");
CtMethod m = CtNewMethod.make("""
    public static void copy(byte[] to, byte[] from) {
        int count = from.length;
        int i = 0;
        switch (count % 8) {
            case 7: to[i] = from[i++];
            case 6: to[i] = from[i++];
            case 5: to[i] = from[i++];
            case 4: to[i] = from[i++];
            case 3: to[i] = from[i++];
            case 2: to[i] = from[i++];
            case 1: to[i] = from[i++];
            case 0:;
        }
        while (i < count) {  
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
        }
    }
}""", cc);

cc.addMethod(m);

def dev = cc.toClass().newInstance()
def to = new byte[3]
dev.copy(to, [1,2,3] as byte[])

to.each { println it }
文字列の八方向検索 (Nested Flatten)
しかるべきアルゴリズムを思いつかない時点でアウトですね。データの方を起点にしてみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
data = [
  "リオウウリウ",
  "ウオリウオリ",
  "オリリオリウ",
  "リリオオウオ"]

w = data[0].size()
h = data.size()

pattern = 'ウオリ'

def scan(direc, sx, sy, dx, dy) {
  def s = ''
  (x,y) = [sx, sy]
  while (x in 0..<w && y in 0..<h) {
    s += data[y][x]
    x += dx
    y += dy
  }
  if (s.startsWith(pattern)) {
    println "($sx, $sy),"+direc
  }
}

(0 ..< h).each { y ->
  (0 ..< w).each { x ->
    scan("右",   x, y, +1,  0)
    scan("左",   x, y, -1,  0)
    scan("下",   x, y,  0, +1)
    scan("上",   x, y,  0, -1)
    scan("右下", x, y, +1, +1)
    scan("左上", x, y, -1, -1)
    scan("左下", x, y, -1, +1)
    scan("右上", x, y, +1, -1)
  }
}

「文字列の八方向検索」を作るなら、JGGUGに入るべき!

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
data = ["リオウウリウ",
        "ウオリウオリ",
        "オリリオリウ",
        "リリオオウオ"]
w = data[0].size()
h = data.size()

checkdata = new int[h][w]
answer = 'ウオリ'

def findAnswers(data) {
  def result = []
  for (int i=0; i<data.size(); i++) {
    if (data[i..-1].startsWith(answer)) {
      result += i
    }
  }
  return result
}

def checkAnswer(direc, x, y) {
  println "($x, $y),"+direc
}



// RIGHT
for (int y=0; y< h; y++) {
  s = ''
  for (int x = 0; x< w; x++) {
    s += data[y][x]
  }
  t = findAnswers(s)
  if (t != []) {
    t.each {
      checkAnswer("右", it, y)
    }
  }
}

// LEFT
for (int y=0; y<data.size(); y++) {
  s = ''
  for (x = w-1; x>=0; x--) {
    s += data[y][x]
  }
  t = findAnswers(s)
  if (t != []) {
    t.each {
      checkAnswer("左", w-it-1, y)
    }
  }
}

// DOWN
for (x = 0; x<w; x++) {
  s = ''
  for (int y=0; y< h; y++) {
    s += data[y][x]
  }
  t = findAnswers(s)
  if (t != []) {
    t.each {
      checkAnswer("下", x, it)
    }
  }
}

// UP
for (x = 0; x<w; x++) {
  s = ''
  for (int y=h-1; y>= 0; y--) {
    s += data[y][x]
  }
  t = findAnswers(s)
  if (t != []) {
    t.each {
      checkAnswer("上", x, h-1-it)
    }
  }
}


// TOPLEFT->BOTTOMRIGHT
for (i=0; i<w+h-1; i++) {
  x = Math.max(0, w-1-i); y=Math.max(0, -w+i+1)
  s = ''
  while (0<=x && x<w && 0<=y &&y<h) {
    s += data[y][x]
    x++
    y++
  }
  t = findAnswers(s)
  if (t != []) {
    t.each {
      checkAnswer("右下", Math.max(0, w-1-i)+it, Math.max(0, -w+i+1)+it)
    }
  }
}

// BOTTOMRIGHT->TOPLEFT
for (i=0; i<w+h-1; i++) {
  x = Math.min(w-1,i); y = Math.min(h-1, h-2-i+w)
  s = ''
  while (0<=x && x<w && 0<=y &&y<h) {
    s += data[y][x]
    x--
    y--
  }
  t = findAnswers(s)
  if (t != []) {
    t.each {
      checkAnswer("左上", Math.min(w-1,i)-it, Math.min(h-1, h-2-i+w)-it)
    }
  }
}

// TOPRIGHT->BOTTOMLEFT
for (i=0; i<w+h-1; i++) {
  x = Math.min(w-1,i);  y=Math.max(0, -w+i+1)
  s = ''
  while (0<=x && x<w && 0<=y &&y<h) {
    s += data[y][x]
    x--
    y++
  }
  t = findAnswers(s)
  if (t != []) {
    t.each {
      checkAnswer("左下", Math.min(w-1,i)-it, Math.max(0, -w+i+1)+it)
    }
  }
}

// BOTTOMLEFT->TOPRIGHT
for (i=0; i<w+h-1; i++) {
  x = Math.max(0,w-1-i); y = Math.min(h-1, h-2-i+w)
  s = ''
  while (0<=x && x<w && 0<=y &&y<h) {
    s += data[y][x]
    x++
    y--
  }
  t = findAnswers(s)
  if (t != []) {
    t.each {
      checkAnswer("右上", Math.max(0,w-1-i)+it, Math.min(h-1, h-2-i+w)-it)
    }
  }
}
PageRankの計算 (Nested Flatten)
ほとんどJava版と同じですが、入力データの形式はお題オリジナルのフォーマットに合わせたことと、固有ベクトルの正規化にクロージャを使うなど、少しだけ工夫してみました。 Commons Mathの行列計算ライブラリも試したのですが、残念ながらV2.0でも非対称行列の対角化はサポートされていませんでした。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import Jama.Matrix

def data = [
    1: [2, 3, 4, 5, 7],
    2: [1],
    3: [1, 2],
    4: [2, 3, 5],
    5: [1, 3, 4, 6],
    6: [1, 5],
    7: [5],
]

def dimension = data.size()
def mat = new double[dimension][]

for(int i=0; i<dimension; i++){
    mat[i] = new double[dimension]
    def numLinks = data[i+1].size()
    def invNumLinks = 1/numLinks
    for(int j=0; j<numLinks; j++){
        mat[i][data[i+1][j]-1] = invNumLinks
    }
}

def tmat = new Matrix(mat.asType(double[][])).transpose()
def eigVec = tmat.eig().getV().transpose().getArray()[0]
def norm1 = new Matrix(eigVec, eigVec.size()).norm1()
eigVec = eigVec.collect{ it/norm1 }
println eigVec
最大公約数(除算禁止) (Nested Flatten)

芸無し。SiroKuroさんのC#のの移植です。

1
2
3
4
5
fib1999 = new BigInteger("2611005926183501768338670946829097324475555189114843467397273230483773870037923307730410719313972291638157639230613843870597997481070930648667960025707364078851859017098672504986584144842548768373271309551281830431960537091677315014266625027123872238011234749984205478230617988978500613170516952885123444971471854671812569739975450866912490650853945622130138277040986146312325044424769652148982077548213909414076005501");

fib2000 = new BigInteger("4224696333392304878706725602341482782579852840250681098010280137314308584370130707224123599639141511088446087538909603607640194711643596029271983312598737326253555802606991585915229492453904998722256795316982874482472992263901833716778060607011615497886719879858311468870876264597369086722884023654422295243347964480139515349562972087652656069529806499841977448720155612802665404554171717881930324025204312082516817125");

println fib1999.gcd(fib2000)
ライフゲーム (Nested Flatten)

sawatさんのJava版、ほぼそのまま・・すんません。 @Delegateをつかってみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import java.awt.*;
import java.util.Random;
import java.util.concurrent.*;
import javax.swing.*;

public class Life {

    @Delegate JFrame frame = new JFrame()

    private boolean[] cells;
    private final int pitch, w, h;

    public Life(final int _w, final int _h, final double rate) {
        w = _w;
        h = _h;
        
        pitch = 5;
        cells = new boolean[h*w];

        initialize(rate);
        
        contentPane.add(new JLabel(new Icon() {
            int getIconHeight() { h * pitch + pitch }
            int getIconWidth() { w * pitch + pitch }
            public void paintIcon(Component c, Graphics g, int x, int y) {
                g.color = Color.BLUE
                [0..<h, 0..<w].combinations().each {
                  int i = it[0]
                  int j = it[1]
                  if(cells[at(i,j)]) g.fillRect(j*pitch, i*pitch, pitch, pitch);
                }
            }
        }));
        
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate( {
            update();
            repaint();
        }, 1000L, 200L, TimeUnit.MILLISECONDS);
    }
    
    private void initialize(double rate) {
        final Random random = new Random(System.currentTimeMillis());
        [0..<h, 0..<w].combinations().each {
          cells[at(it[0], it[1])] = random.nextDouble() < rate;
        }
    }
    private int at(int i, int j) {
        return i*w + j;
    }
    
    protected void update() {
        boolean[] newG = cells.clone();
        
        [0..<h, 0..<w].combinations().each {
          newG[at(it[0], it[1])] = next(it[0], it[1]);
        }
        cells = newG;
    }

    private boolean next(int i, int j) {
        final int u = (i+h-1)%h, d = (i+1)%h, l = (j+w-1)%w, r = (j+1)%w;
        int count = 0;
        if(cells[at(u, j)]) count++;
        if(cells[at(u, r)]) count++;
        if(cells[at(i, r)]) count++;
        if(cells[at(d, r)]) count++;
        if(cells[at(d, j)]) count++;
        if(cells[at(d, l)]) count++;
        if(cells[at(i, l)]) count++;
        if(cells[at(u, l)]) count++;
        
        return ((cells[at(i, j)] && (count == 2 || count == 3))  ||
                (!cells[at(i, j)] && count == 3));
    }
}


Life f = new Life(20, 20, 0.3);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
居眠り床屋問題 (Nested Flatten)
GParallelizer改め、GPars(Groovy Parallel Systems)のActorモデルを使って書いてみました。
GPARSのドキュメントを良く読んでないのですが、排他制御あたりはもう少しましに書ける気がするな。

実行例はこんな感じ

$ groovy barber.groovy
[1]来店 1
床屋、目覚める
[13]散髪開始 1
[1]来店 2
[13]散髪完了 1
[13]散髪開始 2
[1]来店 3
[1]来店 4
[1]来店 5
[1]満席で立ち去る 5
[13]散髪完了 2
[12]散髪開始 3
[1]来店 6
[12]散髪完了 3
[13]散髪開始 4
[1]来店 7
[13]散髪完了 4
[11]散髪開始 6
[1]来店 8
[11]散髪完了 6
[13]散髪開始 7
[13]散髪完了 7
[13]散髪開始 8
[13]散髪完了 8
床屋、眠る
[1]来店 9
床屋、目覚める
[12]散髪開始 9
[1]来店 10
[1]来店 11
[1]来店 12
[1]満席で立ち去る 12
[12]散髪完了 9
[11]散髪開始 10
[1]来店 13
[1]来店 14
[1]満席で立ち去る 14
[11]散髪完了 10
[11]散髪開始 11
[1]来店 15
[11]散髪完了 11
[11]散髪開始 13
[1]来店 16
[11]散髪完了 13
[13]散髪開始 15
[13]散髪完了 15
[13]散髪開始 16
[13]散髪完了 16
床屋、眠る
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import org.gparallelizer.actors.pooledActors.AbstractPooledActor
import static Rnd.randomValue

class Rnd {
  static random = new Random()
  static randomValue(IntRange r) {
    random.nextInt(r.to - r.from) + r.from
  }
}

class BarberShop extends AbstractPooledActor {

  Barber barber;
  def seat = []

  void visit(Customer c) {
    c.arrive()
    if (seat.size() < 3) {
      synchronized (seat) {
        while (seat.size() >= 3) {
        }
        if (seat.size() == 0) {
          println "床屋、目覚める"
        }
        seat += c
        c.bbs = this
        barber.send c
      }
    }
    else {
      c.goneSeatFull()
    }
  }

  void bye(Customer c) {
    synchronized (seat) {
      seat.remove(c)
      if (seat.size() == 0) {
        println "床屋、眠る"
      }
    }
  }

}

class Barber extends AbstractPooledActor {
  void act() {
    loop {
      react { Customer c ->
        c.startCut()
        Thread.sleep(randomValue(100..400))
        c.finishCut()
      }
    }
  }
}

class Customer {
  def tid() {
    Thread.currentThread().id
  }

  String name
  BarberShop bbs

  void arrive() { println "[${tid()}]来店 $name" }
  void startCut() { println "[${tid()}]散髪開始 $name" }
  void finishCut() {
    println "[${tid()}]散髪完了 $name"
    bbs.bye(this)
  }
  void goneSeatFull() { println "[${tid()}]満席で立ち去る $name" }
}

bb = new Barber()
bb.start()

b = new BarberShop(barber:bb)
(1..16).each {
  if (it == 9) {
    Thread.sleep(1200)
  }
  else {
    Thread.sleep(randomValue(0..200))
  }
  def c = new Customer(name:it)
  b.visit(c)
}

bb.join()
除算・余剰を使わずに閏年 (Nested Flatten)

groovyのカバレッジをあげるべく、C#の投稿を真似てみました。 groovyでは、正規表現とマッチさせる演算子があるので、100の倍数チェックで使ってみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def m4(y){ (y & 3) == 0 }
def m16(y){ (y & 15) == 0 }
def m100(y){ "$y" ==~ /.*00$/ }
def isLeapYear(y){m4(y) && (!m100(y) || m16(y))}

println isLeapYear(1900)
println isLeapYear(2000)
println isLeapYear(2008)
println isLeapYear(2009)
println isLeapYear(2100)
マルバツゲーム (Nested Flatten)

groovyのカバレッジをあげるべく、書いてみました。動かしたら遅かったです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class Report{
    def circleWin = 0
    def xrosWin = 0
    def tie = 0
}

class Game {
    def curPlayer
    def circlePlayer
    def xrosPlayer
    def report
    def board
    def play(){
        board = new Board()
        circlePlayer.type = 'CIRCLE'
        xrosPlayer.type = 'XROS'
        curPlayer = xrosPlayer

        while( !board.getWinner() ){
            curPlayer.set(board)
            swapPlayer()
        }
        def winner = board.getWinner()
        if (winner == 'CIRCLE')   report.circleWin ++
        if (winner == 'XROS')     report.xrosWin ++
        if (winner == 'TIE')      report.tie++
    }
    def swapPlayer(){
        curPlayer = (curPlayer == circlePlayer) ? xrosPlayer : circlePlayer
    }
}

class Player {
    def type
    def set(board){
        board.set(select(board.available()),type[0])
    }
    def select(available){
        def idx = (Math.floor(Math.random() * available.size())) as int
        available[idx]
    }
}

class Board {
    def field = []
    def winPattern = [ [0,1,2], [3,4,5], [6,7,8],
                       [0,3,6], [1,4,7], [2,5,8],
                       [0,4,8], [2,4,6]]
    Board(){
        9.times{field[it] = ''}
    }
    def available(){
        def result = []
        field.eachWithIndex{var, idx ->
            if (!var) result << idx
        }
        result
    }
    def getWinner(){
        def winner = ''
        winPattern.each{ pattern ->
            def var = ''
            pattern.each{ idx ->
                var += field[idx]
            }
            switch (var){
            case 'CCC': winner = 'CIRCLE'; break;
            case 'XXX': winner = 'XROS'; break;
            }
        }
        if (winner == '' && available() == []) winner = 'TIE'
        winner
    }
    def set(idx, var){ field[idx] = var }
}

def report = new Report()
def player1 = new Player()
def player2 = new Player()

10000.times{
    new Game(circlePlayer:player1, xrosPlayer:player2, report:report).play()
}

println report.dump()
LL Golf Hole 9 - トラックバックを打つ (Nested Flatten)

パラメータをマップ化してみた。

はてな記法つかえるのかな??

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
>|groovy|
// 一度使用したtitle、urlではトラックバックできないので、毎回変更するために
// #の出力数を指定
def n = args[0].toInteger()
def params = [
    title:"http://ja.doukaku.org/207/${'#'*n}",
    excerpt:"trackback+from+LL+Golf+Hole+9.",
    url:"http://ja.doukaku.org/207/${'#'*n}",
    blog_name:"http://ja.doukaku.org/207/${'#'*n}",
]

new URL("http://d.hatena.ne.jp/takano32/20080905").openConnection().with{
    requestMethod = "POST"
    doOutput = true
    outputStream << params.collect{ "${it.key}=${it.value}" }.join("&")
    System.out << inputStream
    disconnect()
}
||<

つかえなかた・・

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 一度使用したtitle、urlではトラックバックできないので、毎回変更するために
// #の出力数を指定
def n = args[0].toInteger()
def params = [
    title:"http://ja.doukaku.org/207/${'#'*n}",
    excerpt:"trackback+from+LL+Golf+Hole+9.",
    url:"http://ja.doukaku.org/207/${'#'*n}",
    blog_name:"http://ja.doukaku.org/207/${'#'*n}",
]

new URL("http://d.hatena.ne.jp/takano32/20080905").openConnection().with{
    requestMethod = "POST"
    doOutput = true
    outputStream << params.collect{ "${it.key}=${it.value}" }.join("&")
    System.out << inputStream
    disconnect()
}
METHINKS IT IS A WEASEL (Nested Flatten)

作ってはみたものの、metaClassを多用したせいなのかロジックが悪いのか、遅い・・・

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env groovy
final RANDOM = new Random()
final TARGET = "METHINKSITISAWEASEL"
final WORDS_COUNT = 300

final CHARS = "A".."Z"
CHARS.metaClass.random = {
    delegate[RANDOM.nextInt(delegate.size())]
}
String.metaClass.define{
    getDiff{
        def d = 0
        for( def i in 0..<delegate.size() ){
            d += Math.abs(TARGET[i] <=> delegate[i])
        }
        d
    }
    getNewWord{
        def clist = delegate.chars as List
        clist[RANDOM.nextInt(clist.size())] = CHARS.random()
        clist.join("")
    }
}
def words = []

WORDS_COUNT.times{
    def chars = []
    for( def i in 0..<TARGET.size() ){
        chars << CHARS.random()
    }
    words << chars.join("")
}

while( words[0] != TARGET ){
    words = (words * 3)*.newWord.sort{
        it.diff
    }[0..<WORDS_COUNT]
    println words[0]
}
一部のHTMLタグを通すフィルタ (Nested Flatten)

たぶんこれでできているのではないかな?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env groovy

String.metaClass.define{
    escapeHtml{
        delegate.replace("<", "&lt;").replace(">", "&gt;")
    }
}

def text = System.in.text
// 属性値の置換
text = text.replaceAll(/(?<="|').+?[^\\](?='|")/){
    it.escapeHtml()
}
// HTMLタグの置換
text = text.replaceAll(/<\/?(\w+).*?\/?>/){ all, name ->
    def ret = ""
    switch( name ){
        case ~/(?i)a/:
            // aタグhref属性のみURLエンコード処理
            ret = all.replaceAll(/(?<=href="|').+?[^\\](?='|")/){
                it.replace("&lt;","%3C").replace("&gt;", "%3E")
            }
            break
        case ~/(?i)br|strong/:
            ret = "<${name} />"
            break
        default:
            ret = all.escapeHtml()
            break
    }
    ret
}

println text
行列式の計算 (Nested Flatten)

Javaからの移植。これは実に簡単。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// from Java

double determinant(double[][] matrix) {
  if (matrix.length == 0) return 0
  if (matrix.length != matrix[0].length) {
    // 他の行の長さはチェックしていない
    throw new IllegalArgumentException()
  }
  return determinant(matrix, new Stack<Integer>())
}


double determinant(double[][] matrix, Stack<Integer> except) {
  if (matrix.length == except.size()) {
    return 1.0
  }
  double result = 0.0
  int y = except.size()
  int x = 0
  for (int sign = 1; x < matrix.length; x++) {
    if (!except.contains(x)) {
      except.push(x)
      result += sign * matrix[y][x] * determinant(matrix, except)
      except.pop()
      sign *= -1
    }
  }
  return result
}

println(determinant([[1,2],
                     [3,4]] as double[][]))
println(determinant([[1,2,3,4],
                     [2,3,4,1],
                     [3,4,1,2],
                     [4,1,2,3]
                     ] as double[][]))
lessの実装 (Nested Flatten)

「とりあえず動いた」というレベルです。 ほんとは、Line概念をもうちょっと作り込みたいのですが、とりいそぎ。前方サーチと広報サーチも共通部を括りだせるはずですけどやってませんです。ANSIエスケープシーケンスをサポートする端末で動作します。画面の幅と高さはハードコーディング。

効率の話としては、メモリマップドファイルをつかってるのでどんな巨大なファイルでも開くのは一瞬です。前後移動も同様です。ただし、検索するとさすがに全体をなめるので、見つからなかった場合に末尾まで見に行くのはおそいでしょう。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import java.nio.*
import java.nio.channels.*

ByteBuffer.metaClass.getAt = { int index -> get(index) }

class Less {
  static PAGE_HEIGHT=20
  static PAGE_WIDTH=76
}

class TextBuffer {

  MappedByteBuffer mbb
  long curPos = 0
  long size;
  String fileName

  TextBuffer(String fn) {
    fileName = fn
    def fc = new FileInputStream(fn).getChannel()
    mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size())
    size = fc.size()
  }

  void clear() {
    print "\033[2J"
  }

  def getLine(pos) {
    def sb = new StringBuilder()
    def ch
    while (pos < size && (ch = mbb[(int)pos]) != '\n') {
      sb.append(new String(ch))
      pos = Math.min(pos+1, size-1)
    }
    sb.toString()
  }

  void showPage(pat = null) {
    def pos = curPos
    clear()
    println "\033[1m"+fileName+"\033[m" + ('-' * (Less.PAGE_WIDTH-fileName.size()))
    Less.PAGE_HEIGHT.times {
      def str = getLine(pos)
      if (pat != null) {
        str = str.replaceAll('('+pat+')', "\033[7m\$1\033[m")
      }
      println str
      pos = getNextLinePos(pos)
    }
    println '-'*Less.PAGE_WIDTH
    print "> "
  }

  long getNextLinePos(pos) {
    def ch
    while (pos < size && (ch = mbb[(int)pos]) != '\n') {
      pos++
    }
    if (pos == size) {
      return pos
    }
    pos+1
  }

  void forward(n) {
    n.times {
      curPos = getNextLinePos(curPos)
    }
  }

  void searchForward(pat) {
    if (pat == null) { return }
    def pos = curPos
    def str = getLine(pos)
    while (pos < size && !(str =~ pat)) {
      pos = getNextLinePos(pos)
      str = getLine(pos)
    }
    if (str =~ pat) {
      curPos = pos
    }
  }

  long getPrevLinePos(pos) {
    pos = Math.max(pos-2, 0)
    def ch
    while ((ch = mbb[(int)pos]) != '\n') {
      pos = Math.max(pos-1, 0)
      if (pos == 0) {
        return pos
      }
    }
    Math.min(pos+1, size-1)
  }

  void backward(n) {
    n.times {
      curPos = getPrevLinePos(curPos)
    }
  }

  void searchBackward(pat) {
    if (pat == null) { return }
    def pos = curPos
    def str = getLine(pos)
    while (pos > 0 && !(str =~ pat)) {
      pos = getPrevLinePos(pos)
      str = getLine(pos)
    }
    if (str =~ pat) {
      curPos = pos
    }
  }

}


tb = new TextBuffer(args[0])
lastPattern = null
tb.showPage()
System.in.eachLine { key ->
  if (key ==~ /^n/) {
    tb.forward(Less.PAGE_HEIGHT)
    lastPattern = null
  }
  else if (key ==~ /^[pb]/) {
    tb.backward(Less.PAGE_HEIGHT)
    lastPattern = null
  }
  else if (key ==~ /q/) {
    System.exit(0)
  }
  else if (key ==~ /^([\/\?])([^\n]*)$/) {
    def g1 = java.util.regex.Matcher.lastMatcher.group(1)
    def g2 = java.util.regex.Matcher.lastMatcher.group(2)
    if (g1 == '/') {
      if (g2 == "") {
        tb.forward(1)
        g2 = lastPattern
      }
      tb.searchForward(g2)
    }
    else if (g1 == '?') {
      if (g2 == "") {
        tb.backward(1)
        g2 = lastPattern
      }
      tb.searchBackward(g2)
    }
    lastPattern = g2
  }

  tb.showPage(lastPattern)
}
正しい文(クイズ) (Nested Flatten)

普通に。

1
2
3
4
5
6
7
8
9
#!/usr/bin/env groovy
def file = new File("test.txt")
def chars = file.text.chars

print "この文は"
print( ('0'..'9').collect{
    "${it}が${chars.count(it)}個"
}.join(",") )
print "あります。"
ナイツ関数(ボケの方) (Nested Flatten)
javaの解法を参考にさせていただきました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/env groovy
final MIN_SIMILARITY_RATE = 0.51

def wordList = []
["fam25_10.txt", "fam40_25.txt", "fam55_40.txt", "fam70_55.txt"].each{
    Collections.addAll(wordList, new File(it).text.split(/\s/))
}
def file = new File("inputSample.txt")
assert wordList
assert file?.exists()

println file.text.replaceAll(/(?m)\S+/){ word ->
    def convertList = [ word, *wordList.findAll{ other ->
        getSimilarityRate(word, other) >= MIN_SIMILARITY_RATE
    } ]
    Collections.shuffle(convertList)
    convertList[0]
}

double getSimilarityRate(String str1, String str2){
    def len1 = str1.size()
    def len2 = str2.size()

    def matrix = new int[len1+1][len2+1]
    
    for(int i = 0; i < matrix.size(); i++){
        matrix[i][0] = i
    }
    for(int i = 0; i < matrix[0].size(); i++){
        matrix[0][i] = i
    }
    
    for(int i = 0; i < len1; i++){
        for(int j = 0; j < len2; j++){
            int cost = (str1[i] == str2[j]) ? 0 : 1
            matrix[i+1][j+1] = [matrix[i][j+1] +1, matrix[i+1][j] +1, matrix[i][j] +cost].min()
        }
    }
    
    def longer = [len1, len2].max()
    (longer - matrix[len1][len2])/longer
}
ファイル内の重複行削除(後優先) (Nested Flatten)

素朴に。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
list = []

new File(args[0]).eachLine {
  if (list.contains(it) != null) {
    list.remove(it)
  }
  list += it
}

list.each {
  println it
}
ビンゴの結果を整形表示 (Nested Flatten)

率直に言ってgroupByを使うべきケースでしょうこれは。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def bingo(n) {
   (1..n).toList().sort{ Math.random() }
}

def bingoprint(n) {
  def bingo = bingo(n)
  (1..n).groupBy{(it-1).intdiv(10)}.each{k,v->
    v.each{printf "%3d",it};println()
    v.each{printf "%3d",bingo[it-1]};println("\n")
  }
}

bingoprint(30)
bingoprint(35)
Hello, world! PDF版 (Nested Flatten)

[Java版の移植です。]"http://ja.doukaku.org/comment/2487/" Groovy-1.7-beta-1のGrab記法使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Grab('com.lowagie:itext:2.1.3')
import com.lowagie.text.*
import com.lowagie.text.pdf.*

TEXT = "Hello, World!";

new Document(PageSize.B0.rotate()).with {
  PdfWriter.getInstance(it, new FileOutputStream("HelloWorld.pdf"))
  open()
  bf = BaseFont.createFont(BaseFont.TIMES_ROMAN, "US-ASCII", false)
  float size = (right() - left()) / bf.getWidthPoint(TEXT, 1.0f);
  add(new Paragraph(TEXT, new Font(bf, size)))
  close()
}
next >>

Index

Feed

Other

Link

Pathtraq

loading...