Language detail: Groovy
Coverage: 86.80%
|
number of '+' ratings |
contribution for coverage |
Unsolved challenges
- 文字列で+を表示する (Nested Flatten)
- 年賀はがきの当せん番号 (Nested Flatten)
- 箱詰めパズルの判定 (Nested Flatten)
- 関数やメソッドのソースの平均行数 (Nested Flatten)
- コレクションの実装 (Nested Flatten)
codes
文字列の八方向検索
(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
床屋、眠る
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の倍数チェックで使ってみました。
see: C#
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("<", "<").replace(">", ">")
}
}
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("<","%3C").replace(">", "%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)
next >>
[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()
}
|




uehaj #9669() [ Groovy ] Rating0/0=0.00
Groovyからバイトコードを操作するため、バイトコード生成のためのライブラリ「javassist」を使っています。ただ、残念なことにjavassistは抽象度が高すぎて、バイトコードの指定にJavaソースコードを使うこともできてしまいます。もちろんバイトコードインストラクションレベルでの指定もできるのですが、あえてするのも意味ないのでこのままで。
Groovyにとっては「インラインJava」ができる例として。
@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 }Rating0/0=0.00-0+
[ reply ]