プラウダ

モスクワの報道は三つのカテゴリーにわかれている。すなわち「真実」「たぶん真実」及び「真実性のないもの」の三つである。 第一のカテゴリーには時報、第二のカテゴリーには天気予報、そして第三のカテゴリーには他の全てが含まれている。

bottleとvueでウェブアプリの骨組み

ちょいと現職で必要があり、趣味半分でPythonフレームワークであるbottleとJavaScriptフレームワークであるvue使ってウェブアプリの骨組みみたいなの作ってみました。サンプルはこちらhttp://lab.klaraworks.net:8000/。ソースはGithub
https://github.com/kirisaki/bottle_vue
)に置いてあります*1

どんな感じでやってるかって言うとapp.pyがRESTっぽいAPI通してJSONを送り出してJavaScript部分で表示するって感じです。vue-routerも使いSPAにしてあります。あとは他に必要なAPI作ったり、DB接続させたりすれば結構簡単にウェブアプリ作れそうで楽しそうです。vuexも気になるので触りたいですね。

*1:これがやりかった

Vue.jsでスクロール範囲内に入るとクラス付加するやつ

ウェブサイト作りながら少し成果上がったので公開していくことにする。作ったのはスクロールして画面内に入ったらクラス付加するやつ。簡単な例だけどメモとして。

まずvueファイル。

// in-screen.vue

<template>
  <div v-bind:class="{active: isInScreen}">
    <slot></slot>
  </div>
</template>

<script>
export default {
  props : {
    offset:{
      type: Number,
      default: 0
    }},
  data() {
    return {
      scrollY: 0,
      height: 0,
      position: 0,
    }
  },
  mounted() {
    window.addEventListener('scroll', this.onScroll)
    window.addEventListener('resize', this.onResize)
    window.addEventListener('load', ()=> {
      this.onScroll()
      this.onResize()
    })
  },
  computed:{
    isInScreen(){
      if(this.scrollY > this.position + this.offset){
         return true
      }else{
        return false
      }
    }
  },
  methods: {
    onScroll () {this.scrollY = window.pageYOffset},
    onResize () {this.height = document.documentElement.clientHeight} ,
    getPosition () {
      if(this.$el){
        return this.$el.getBoundingClientRect().top +
            this.scrollY -
            this.height
        }else{
            return 0
        }
      },
    }
 }
</script>

isInScreenを算出プロパティとして定義させて必要な時に再取得させる。んだけど他のスクロール量とかはリアクティブに出来ないのかな。要検討。CSS書いてないけどのファイル内でのスコープ限定して書けるらしい。んで動かすのがこれ。

// app.js
import Vue from 'vue'
import InScreen from './in-screen.vue'

const sweetScroll = new SweetScroll();
new Vue({
  el: '#app',
  components: {
    "in-screen": InScreen,
  },
})

コンポーネントごとにファイルまとめられるのでいい感じがする。JSfiddleで動作でも作って貼り付けたかったけど、単一ファイルコンポーネントの動かし方がいまいちよーわからんかったので割愛。サイトで使ったコンポーネントはどんどん上げていきたい。

知識のインストール、バーストモードで

雑に取った有給をウェブサイトの構築に費やしてます。いや、ウェブサイトの構築というよりかはツールの使い方でしょうか。昨日から今日にかけてGit、Sass、pug、gulpの使い方をとりあえず覚えた。node.jsがJavascriptってだけで毛嫌いしてたけど、本当にすみませんと言うしか無い。アプリケーション使うだけならめっちゃ便利でした。

2日間でめっちゃ知識をインストールした感じあるけど、実際のところ負荷はそんなにない感触。せいぜいツールの使い方だけだしSassなんかはCSSに色つけた感じだしね。Sassのイディオム的なものは検索して見つかるけど、どんな感じにファイル分けするかとかどこでどう変数使うかみたいなノウハウってどうやって手に入るんだろう。というかCSS書いてた時代も雰囲気で書いてたし、そのへんの知識がまるでない。

あとVue.jsを触りたいんだけど現状前に作ったHTML・CSSをpug・Sassに変換するのがやっとという感じ。pugはともかくSassの方は単純に変換しただけではメリットないのでそのへんの共通化とかも考えないといけないので更に辛い。Sassっぽい書き方というのがつかめれば楽なんだろうけどなー。Javascriptに関してはCoffeescriptの導入も考えましたが「最近イケてない」らしいので見送り。TypeScriptは導入するメリットそんなないかなと思ったので結局素のJavascriptに戻るのであった。辛い。Purescript*1も楽しそうだけど、流石に学習コストが高い。

そうそう、gulpでAの処理終わってからBの処理するってのを書いてたんですが

gulp.task('pug-reload',['pug'],function(){
		return browserSync.reload();
});
gulp.task('sass-reload',['sass'],function(){
		return browserSync.reload();
});
gulp.task('js-reload',['js'],function(){
		return browserSync.reload();
});

って感じにボイラープレートになってしまって何かいい方法ないんかなって頭捻ってます。

gulp.task('seq-reload',[引数],function(){
		return
 		(引数に書いてあるtask実行)
		browserSync.reload();
});

みたいに引数で処理分けることができればいいんですが。「gulp 引数」でググってもコマンドライン引数についてしかでてこないし。

*1:HaskellJavascriptにするやつ

やりたいことの雑多なメモ

技術ってのは使わないと衰えるもんで。そんな理由もありまして現在有給をぶち込みつつウェブサイトを改装すべくいろいろ調べてます。調べた結果Gitのリポジトリ作り出す羽目になってるのは???ってなったけどちゃんと理由があってのことなんですよ。やりたいこと優先度高い順に書き出すとこんな感じ。

Gitによるソースコードの管理はこんなページもあったので参考にしたい。
qiita.com
VPSアカウント持ってるんでそこにオレオレリポジトリを作りいい感じで開発できたらな~という感じ。感じが多くてイメージがふわふわしてる。

Vue.jsは簡潔に書けるって噂なので試したいですね。jQueryプラグインでゴリゴリやってみたけどオリジナルのモーダルボックス出すだけでソースコードがさっぱりわけの分からない感じになったのでその辺を簡潔に書きつつリッチなUIを実現したい。Sassも素のCSS書いてるとよくわからないクラスとかでてきて混迷を極めてくるのでやはり導入したいところ。

4つ目のテンプレートエンジンの導入はちょっとむずかしいところ。作品ページに個別URL振って見せたいんですけどそうなるとテンプレートエンジン使って静的にページを生成するしか無いのかなと。.htaccess使ってサーバサイドでスクリプト動かすにしても結局サーバ側での処理が必要だろうと思うし。でもVue.jsのルーティングで解決できるのか……?リサーチ不足なのでなんとも。

最後のBrowsersyncみたいなのを作るのは完全に趣味なんだけどやりたい。構想としてはファイルの変更を察知したらWebsocket経由でHTMLに組み込んだJavascriptに命令を送り込んで自動更新する、みたいなやつを最低限やりたい。それに加えテンプレートエンジンとWebサーバも組み込んで静的ページを生成するフレームワーク的なものを作りたい……まで行くとちょっと風呂敷を広げ過ぎな感じはしますね。

そんな感じで妄想だけは続くのだ。

HaskellでNクイーンとナイトツアー

所用で行き当たりばったりなJavaScript書いてたら飽きたので前から手を付けようと思って手を付けてなかったHaskellにでも手つけてみっかという感じ。すごいH本は暇つぶしに何回も読んでるので「りろんはしってる」状態。

Nクイーン

 N \times Nのチェス盤に N個のクイーンを互いに移動先が塞がれないように配置するパズル。クイーンは上下左右と斜め方向どこまでも動ける(飛車と角を足した動き)。例えば N = 5ならこんな配置。

Q . . . .
. . . Q .
. Q . . .
. . . . Q
. . Q . .

とりあえず例とかは検索せず知ってる知識だけで書いていこー。

実践

type Pos = (Int,Int)

isPlace :: Pos -> Pos -> Bool
isPlace x y | fst x == fst y = False
            | snd x == snd y = False
            | abs(fst x - fst y) == abs(snd x - snd y) = False
            | otherwise = True

コマの位置はタプルで行と列を表し、それと置けるかどうか判定する関数。

placeble :: [Pos] -> [Pos]
placeble hist = [(x,length hist) | x <- [0..], all (isPlace (x,length hist)) hist]

前の行までの置いてあるコマの位置のリストを取って次の行に置ける位置を返す。Haskellらしく?無限リスト使ってみたりした。

search :: Int -> Int -> [[Pos]] -> [[Pos]]
search 1 m p = p
search n m p = search (n-1) m (concat (map (\q->(map (\r->q++[r]) (takeWhile (\s->fst s<m) (placeble q)))) p))

探す深さ(行)と深さの最大値、それから解候補を入れて解候補の次の位置に置ける位置を連結する関数。ポイントは次の位置における位置がない場合空リストが返ってくるのでバックトラッキングができてること……だと思う。リスト内包使えばもっときれいに書けたんでないか、と言うかナイトツアーの方ではそうしてる。

solve :: Int -> [[Pos]]
solve n = search n n [[(x,0)]|x<-[0..n-1]]

あとは1行目に置く位置のリスト作ってsearchに突っ込む関数作っておしまい。

Prelude> :l eightqueen.hs
[1 of 1] Compiling Main             ( eightqueen.hs, interpreted )
Ok, modules loaded: Main.
*Main> length $ solve 8
92

 N=8の時の回転合同とかも含めた時における解の数と一致、うまくいきました。あとで調べたら解候補は順列作ってやれば楽って出てきてあーってなったけどきちんとバックトラッキングしてるおかげかこっちのほうが速い気がするのでそれはそれでいいんじゃないかという事にしておいた。

ナイトツアー

別名「騎士の巡歴」。 N \times Mのチェス盤でナイトが一筆書できる手順を探すパズル。ナイト(N)はXの位置に動ける。

. X . X .
X . . . X
. . N . .
X . . . X
. X . X .

 N = 4, M = 3の解の例は以下の通り。

 1   8   3
 4  11   6
 7   2   9
10   5  12

同じく実装例自体は検索せず行ってみる。

import Data.List

type Pos = (Int,Int)

nextmove :: Pos -> [Pos]
nextmove p = [(fst p + x,snd p + y)| x<-[-2,-1,1,2], y<-[-2,-1,1,2], abs x /= abs y]

movable :: Int -> Int -> [Pos] -> [[Pos]]
movable x y hist = [hist++[q]| q<- (nextmove $ last hist), notElem q hist, crop q]
  where crop r = foldl (&&) True  [fst r>=0, snd r>=0, fst r<x, snd r<y]

あとで使うのでData.Listをimport。位置はまたタプルで行列の順。nextmoveは次動ける場所を返す。movableは盤面の縦横と今まで動いてきた位置を取って次動ける場所を連結して返す。はみ出しの処理とかはここ。

isEnd :: Int -> Int-> [Pos] -> Bool
isEnd x y p =  x*y == (length $ nub p)

search :: Int -> Int -> [[Pos]] -> [[Pos]]
search x y p = if null cand then [r | r<-p, isEnd x y r]
  else search x y cand
  where cand = concat[movable x y q | q<-p]

isEndで解候補が終了してるか判定。通ってきた位置の数が盤面の数と一致すればゴールにしてある。一応同じ位置はnubで排除してるけど無くていい。searchで次置ける場所を再帰的に探索。ここでも次動ける場所がなければ連結されないのでバックトラッキングになってる、はず。

solve :: Int -> Int -> [[Pos]]
solve x y = concat[search x y [[(a,b)]| a<-[0..x-1], b<-[0..y-1]]]
Prelude> :l knighttour.hs
[1 of 1] Compiling Main             ( knighttour.hs, interpreted )
Ok, modules loaded: Main.
*Main> length $ solve 3 4
16

一応全スタート地点から探索する関数も書いたけど、そもそも探索範囲が大きすぎてえらい遅い。でも一応正しい結果は出ているということで。

雑感

手続き型だと結構長くなっちゃうけどHaskellだとかなり簡潔に書けたなーという印象。Haskellの力と言うよりリスト内包とかの威力の気もするので他の言語(Python)でも割りと完結に書けそうな気はしますが。

あまりHaskell的?なファンクタ?とかモナド?とかに触れてなかったのでそういうのも触れていきたいですね。

その前に冬コミの原稿しなきゃ……。