phpで使いそうな画像処理のクラス2

前回のコードが時間がないままフレームワークの中で使っていたものを汎用的にしたので
最悪だったのですが
今回はまだマシかと思います。
とりあえず直しただけ多分動く

一つ目は戒めとして残しておきます。

<?php
class ImageChanger{
      const FILE_MAX_LENGTH = 750;
      const COMPRESSION = 60;

      private $target_file;
      private $width;
      private $height;
      private $type;

      function __construct($target){
            $this->target_file = $target;
      }

      /* public method */
      public function getFile(){ return $this->target_file; }

      //画像の縮小
      public function createImage(){ //->bool
            if(file_exists($this->target_file) == false){
                  return false;
            }
            $this->getImageInformation();
            $size = $this->imageSize(self::FILE_MAX_LENGTH);
            //型作り
            $new_image = imagecreatetruecolor($size['width'], $size['height']);

            switch($this->type){
            case 'image/gif':
                  $base_image = imagecreatefromgif($this->target_file);
                  break;
            case 'image/png':
                  $base_image = imagecreatefrompng($this->target_file);
                  break;
            case 'image/jpeg':
            case 'image/jpg':
                  $base_image = imagecreatefromjpeg($this->target_file);
                  break;
            default:
                  return false;

            }
            //型に合わせて作成
            imagecopyresampled($new_image, $base_image, 0, 0, 0, 0, $size['width'], $size['height'],  $this->width, $this->height);
            ImageDestroy($base_image);

            //元データの削除
            if(file_exists($this->target_file)){
                  unlink($this->target_file);
                  $this->target_file = "";
            }
            $file_path = $this->getNewImagePath();

            imagejpeg($new_image, $file_path, self::COMPRESSION);
            ImageDestroy($new_image);

            $this->target_file = $file_path;
            return true;
      }

      //画像の向きを元に戻す
      public function rotateImage(){ //->bool
            if(file_exists($this->target_file) == false){
                  return false;
            }
            $this->getImageInformation();

            if($this->type != "image/jpeg" && $this->type != "image/jpg"){
                  return true;
            }
            //型作り
            $new_image = imagecreatetruecolor($this->width, $this->height);

            $exif = $this->exifInformation($this->target_file);
            if($exif == null){
                  return false;
            }

            $base_image = imagecreatefromjpeg($this->target_file);
            if(isset($exif['IFD0']['Orientation'])){
                  //回転処理
                  $rotate_infos = $this->imageRotation($exif['IFD0']['Orientation']);

                  //反転
                  if(!empty($rotate_infos['mode'])){
                        $base_image = imageflip($base_image, $rotate_infos['mode']);
                  }

                  //回転
                  if($rotate_infos['degrees'] > 0){
                        $base_image = imagerotate($base_image, $rotate_infos['degrees'], 0);
                  }
            }

            //元データの削除
            if(file_exists($this->target_file)){
                  unlink($this->target_file);
                  $this->target_file = "";
            }
            $file_path = $this->getNewImagePath();

            imagejpeg($base_image, $file_path, self::COMPRESSION);
            ImageDestroy($base_image);

            $this->target_file = $file_path;
            return true;
      }


      /* private method */
      //同じ縦横比のまま長いほうが指定した数値になるように縦横を返す
      private function imageSize($max_length){ // -> [int, int]
            if($this->width < $max_length || $this->height < $max_length){
                  $w = $this->width;
                  $h = $this->height;
            }elseif($this->width > $this->height){
                  $ratio = $this->height / $this->width;
                  $w = $max_length;
                  $h = round($w * $ratio);
            }elseif($this->width < $this->height){
                  $ratio = $this->width / $this->height;
                  $h = $max_length;
                  $w = round($h * $ratio);
            }else{
                  $w = $max_length;
                  $h = $max_length;
            }
            $size = ['width' => $w, 'height' => $h];
            return $size;
      }

      private function getNewImagePath(){ // -> string
            $name = str_replace('.', '', microtime(true));
            $filepath = 'tmp/'. $name. '.jpeg';
            return $filepath;
      }

      //file 情報取得
      private function getImageInformation(){ //->void
            $infos = getimagesize($this->target_file);
            $this->width = $infos[0];
            $this->height = $infos[1];
            $this->type = $infos['mime'];
      }


      //exif情報取得
      private function exifInformation(){
            if(file_exists($this->target_file) == false) return null;
            $exif = exif_read_data($this->target_file, 0, true);
            if($exif === false){
                  return null;
            }else{
                  return $exif;
            }
      }

      //イメージの回転修正
      //ファイルのパスをもらって回転の処理に必要な$mode, $degreesを返す
      private function imageRotation($exif){ //-> [string, int]
            if(isset($exif) == false){
                  return ["", 0];
            }
            $degrees = 0;
            $mode = '';

            switch($exif){
            case 1:
                  break;
            case 2:
                  $mode = 'IMG_FLIP_HORIZONTAL';
                  break;
            case 3:
                  $degrees = 180;
                  break;
            case 4:
                  $mode = 'IMG_FLIP_VERTICAL';
                  break;
            case 5:
                  $degrees = 90;
                  $mode = 'IMG_FLIP_HORIZONTAL';
                  break;
            case 6:
                  //$degrees = 90;
                  $degrees = 270;
                  break;
            case 7:
                  $degrees = 90;
                  $mode = 'IMG_FLIP_VERTICAL';
                  break;
            case 8:
                  $degrees = 270;
                  break;
            }

            return ['mode' => $mode, 'degrees' => $degrees];
      }

}

haskellでバブルソート

haskell面白いです。

なんかアプリとか作ってみようかな

main :: IO ()
main  = do
  putStrLn $ (show pre_sort ) ++ " bubbleSorted -> " ++ (show (bubbleSort pre_sort))
  where
    pre_sort = [6, 5, 1, 9, 3, 8, 2, 7, 4]

bubbleSort :: Ord a => [a] -> [a]
bubbleSort [] = []
bubbleSort [a] = [a]
bubbleSort lst = x : (bubbleSort xs)
  where
    (x:xs) = reverse $ bubbleSortSwap lst

bubbleSortSwap :: Ord a => [a] -> [a]
bubbleSortSwap [] = []
bubbleSortSwap [a] = [a]
bubbleSortSwap (x:y:xs)
  | x < y = y : (bubbleSortSwap (x:xs))
  | otherwise = x : (bubbleSortSwap (y:xs))

Haskellでlifeゲームしてみた

haskell でlifegameをして見ました。
haskellですがlifegameを書くだけでここまで楽しいとは思いませんでした。

すごく楽しいですよ。
まだまだ何も詳しくないですがおすすめです。

いっぱいhaskellで書いていきたいですね!
最初はlogが出せないと思って、debugが難しかったのですが
慣れてくると関数型だからこそやりやすくもなって来ますね。

これからどんどん書いていきます!

import System.Random
-- import Debug.Trace

count :: Int
count = 20

pioneer :: Int
pioneer = 100

-- enum
data Status = Live | Death deriving (Show, Enum, Eq)

type Line = [Status]
type Field = [Line]

newLine :: Line
newLine = replicate count Death

newField :: Field
newField = replicate count newLine

-- fieldの描画
writeField :: Field -> IO ()
writeField [] = putStrLn ""
writeField f = do
  writeLine $ head f
  putStrLn ""
  writeField $ tail f

-- lineの描画
writeLine :: Line -> IO ()
writeLine [] = putStr ""
writeLine (Live:x) = do
  putStr "o "
  writeLine x
writeLine (Death:x) = do
  putStr "_ "
  writeLine x

--セルの振る舞いを決める
decideLifes :: Field -> Field -> [[Int]]  -> Field
decideLifes _ t [] = t
decideLifes f t ([x, y]:xs) = decideLifes f (decideLife f t x y) xs

decideLife :: Field -> Field -> Int -> Int -> Field
decideLife f t x y
  | is_exists && ( isUnderPopulation neighbor_count || isOverPopulation neighbor_count ) = deadCells t x y
  | (not is_exists) && isJustPopulation neighbor_count = liveCells t x y
  | otherwise = t
    where
      neighbor_count = getNeighborsCount f x y
      is_exists = isExist f x y

-- 指定されたセルを生き返らせる
liveCells :: Field -> Int -> Int -> Field
liveCells f x y = do
  front ++ [(liveCell line x)] ++ back
    where
      front = take y f
      line = drop y $ take (y+1) f
      back = drop (y+1) f

liveCell :: Field -> Int -> Line
liveCell [l] x = do
  front ++ [Live] ++ back
    where
      front = take x l
      back = drop (x+1) l


-- 指定されたcellの削除
deadCells :: Field -> Int -> Int -> Field
deadCells f x y = do
  front ++ [(deadCell line x)] ++ back
    where
      front = take y f
      line = drop y $ take (y+1) f
      back = drop (y+1) f

deadCell :: Field -> Int -> Line
deadCell [l] x = do
  front ++ [Death] ++ back
    where
      front = take x l
      back = drop (x+1) l

-- 周囲の数を調べる
getNeighborsCount :: Field -> Int -> Int -> Int
getNeighborsCount f x y = do
  foldr (+) 0 $ map trueToOne [leftup, up, rightup, left, right, leftbottom, bottom, rightbottom]
    where
      leftup = (isNotOutOfField (x-1)) && (isNotOutOfField(y-1)) && (isExist f (x-1) (y-1))
      up = (isNotOutOfField (y-1)) && (isExist f x (y-1))
      rightup = (isNotOutOfField (x+1)) && (isNotOutOfField(y-1)) && (isExist f (x+1) (y-1))
      left = (isNotOutOfField (x-1)) && (isExist f (x-1) y)
      right = (isNotOutOfField (x+1)) && (isExist f (x+1) y)
      leftbottom = (isNotOutOfField (x-1)) && (isNotOutOfField (y+1)) && (isExist f (x-1) (y+1))
      bottom = (isNotOutOfField (y+1)) && (isExist f x (y+1))
      rightbottom = (isNotOutOfField (x+1)) && (isNotOutOfField (y+1)) && (isExist f (x+1) (y+1))
      trueToOne q = if q == True then 1 else 0

-- 過疎
isUnderPopulation :: Int -> Bool
isUnderPopulation count = count == 0 || count == 1

-- 過密
isOverPopulation :: Int -> Bool
isOverPopulation count = count >= 4

-- 子作り最適
isJustPopulation :: Int -> Bool
isJustPopulation count = count == 3

--存在している
isExist :: Field -> Int -> Int -> Bool
isExist f x y = getCell f x y  == Live

-- outofrangeが起きないよう
isNotOutOfField :: Int -> Bool
isNotOutOfField num = (isOverZero num) && (isUnderCount num)

isOverZero :: Int -> Bool
isOverZero num =  num >= 0

isUnderCount :: Int -> Bool
isUnderCount num = num < count

-- セル取得
getCell :: Field -> Int -> Int -> Status
getCell f x y = f !! y !! x


-- 初期段階の生存セルの決定
randomBirthday :: Field -> [[Int]]-> Field
randomBirthday f [] = f
randomBirthday f (a:b) = do
  randomBirthday (liveCells f x y) b
    where
      x = head a
      y = head $ tail a


-- リストを前から二つずつペアにする
makePair :: [Int] -> [[Int]]
makePair [] = []
makePair (a:b:c) = [a,b] : makePair c

main = do
  gen <- getStdGen
  let field = newField
      list = take pioneer [1,2..]
      new_field = randomBirthday field $ makePair $ take (pioneer*2) $ (randomRs (0,(count-1)) gen :: [Int])
  writeField new_field
  run new_field $ take 500 [1, 2..]

run :: Field -> [Int] -> IO ()
run f [] = writeField f
run f (x:xs) = do
  writeField field
  run field xs
  where
      _y = take count [0,1 ..]
      _x = take count [0,1 ..]
      pair = [[x, y]| x <- _x, y <- _y]
      tmp = f
      field = decideLifes f tmp pair

swiftでlifeゲーム

swiftを書かなくちゃいけなくなりそうなので練習しました。

lifegameです。
swift使ってるのにいつも通りterminalです。

新しい言語っぽくて描きやすい。
methodを呼び出すときは、一つでも名前付き引数にするのかな?(書かないとエラーが上がるような気がする)
どうなんだろ?

import Darwin

enum Status{
      case Live
      case Death
}

class Field {
      static let LENGTH = 30
      static let PIONEER = 300
      private var cells: [[Status]];
      init(){
            self.cells = [[Status]](repeating: [Status](repeating: Status.Death, count: Field.LENGTH), count: Field.LENGTH)
      }

      /* public function */
      public func randomBirthday(){
            let max = UInt32(Field.LENGTH)
            for _ in 0 ..< Field.PIONEER {
                  let a = Int(arc4random() % max)
                  let b = Int(arc4random() % max)
                  self._liveCell(x: a, y: b);
            }
      }

      public func run() -> Field {
            let tmp = Field()
            tmp.cells = self.cells
            for y in 0 ..< Field.LENGTH {
                  for x in 0 ..< Field.LENGTH {
                        if self._isLiveCell(x: x, y: y) {
                              tmp._liveCell(x: x, y: y)
                        }else{
                              tmp._deadCell(x: x, y: y)
                        }
                  }
            }
            return tmp
      }

      public func write() {
            var text = "";
            for line in self.cells {
                  for l in line {
                        text += (l == Status.Live) ? "o " : "_ "
                  }
                  text += "\n"
            }
            print(text)
      }

      /* private function */
      private func _isLiveCell(x: Int, y: Int) -> Bool {
            let neighbor_count = self._getNeighborsCount(x: x, y: y)
            if self._isExist(x: x, y: y){
                  return !(self._isUnderPopulation(count: neighbor_count) || self._isOverPopulation(count: neighbor_count))
            }else{
                  return self._isJustPopulation(count: neighbor_count)
            }
      }


      private func _liveCell(x: Int, y: Int){
            self.cells[y][x] = Status.Live;
      }
      private func _deadCell(x: Int, y: Int){
            self.cells[y][x] = Status.Death;
      }

      private func _getNeighborsCount(x: Int, y: Int) -> Int {
            var result = 0
            if self._isNotOutOfField(num: x-1) && self._isNotOutOfField(num: y-1) && self._isExist(x: x-1, y: y-1){ result += 1 }
            if self._isNotOutOfField(num: y-1) && self._isExist(x: x, y: y-1){ result += 1 }
            if self._isNotOutOfField(num: x+1) && self._isNotOutOfField(num: y-1) && self._isExist(x: x+1, y: y-1){ result += 1 }
            if self._isNotOutOfField(num: x-1) && self._isExist(x: x-1, y: y){ result += 1 }
            if self._isNotOutOfField(num: x+1) && self._isExist(x: x+1, y: y){ result += 1 }
            if self._isNotOutOfField(num: x-1) && self._isNotOutOfField(num: y+1) && self._isExist(x: x-1, y: y+1){ result += 1 }
            if self._isNotOutOfField(num: y+1) && self._isExist(x: x, y: y+1){ result += 1 }
            if self._isNotOutOfField(num: x+1) && self._isNotOutOfField(num: y+1) && self._isExist(x: x+1, y: y+1){ result += 1 }
            return result
      }

      private func _isUnderPopulation(count: Int) -> Bool {
            return count == 0 || count == 1
      }

      private func _isOverPopulation(count: Int) -> Bool {
            return count >= 4
      }

      private func _isJustPopulation(count: Int) -> Bool {
            return count == 3
      }

      private func _isExist(x: Int, y: Int) -> Bool {
            return self.cells[y][x] == Status.Live
      }

      private func _isNotOutOfField(num: Int) -> Bool {
            return self._overZero(num: num) && self._underCount(num: num)
      }

      private func _overZero(num: Int) -> Bool {
            return num >= 0
      }

      private func _underCount(num: Int) -> Bool {
            return num < Field.LENGTH
      }
}




func main(){
      var field = Field()
      field.randomBirthday()
      field.write()
      for _ in 0..<500 {
            usleep(UInt32(20000))
            field = field.run()
            field.write()
      }
}

main()

pythonでNクイーン作ってみた。

python3でNクイーンを作りました。
LL系の言語の中で人のコードを読まなければいけないときはダントツでpythonがいいです。
読みやすい。(私が描いたpythonが読みやすいかは置いておいて。。。)

class Queen():
    def __init__(self, num):
        self._num = num
        self._count = 0
        self._result = [-1 for i in range(num)]

    #メイン処理
    def run(self, y = 0):
        for x in range(self._num):
            self._init_array(y)
            if self._can_put(x, y) == False: continue
            self._put(x, y)
            if y == self._num - 1:
                self._count += 1
                self._write()
            else:
                self.run(y+1)

    def get_count(self):
        return self._count


    #今チェックしている行以下を初期化
    def _init_array(self, y):
        i = 0
        for i in range(self._num):
            if i >= y: self._result[i] = -1

    # そこにおけるかどうかのチェック:
    def _can_put(self, x, y):
        return (self._result[y] == -1) and (not x in self._result) and (self._slant_check(x, y))

    # 斜めのチェック
    def _slant_check(self, x, y):
        check = True
        tmp1 = y - x
        tmp2 = y + x
        _y = 0
        for _x in self._result:
            if _x == -1: continue
            if _y == _x + tmp1 or  _y == (-_x) + tmp2:
                check = False
            _y += 1
        return check

    #描画
    def _write(self):
        for y in range(self._num):
            line = ""
            for x in range(self._num):
                line += "Q " if self._result[y] == x else ". "
            print(line)
        print("\n")

    # 配列に含まれているかのチェック:
    def _is_include(self, x):
        check = False
        for r in self._result:
            if r == x: check = True
        return check

    def _put(self, x, y):
        self._result[y] = x

def main():
    q = Queen(4)
    q.run()
    print("point: ", q.get_count())

if __name__ == '__main__':
    main()

python人工知能とかやってみようかな?
最近はRubyからPythonにシフトしていこうとか考えてみたりしています。

でもRuby好きなんだよな。。。

Rustでライフゲーム描いてみた。

Rustでライフゲーム描いてみました。
version 1.18.0です。

型を正しく決めなければ後でうごかなくなってしまって、キャストまみれになってしまっていて
うわぁー汚いって感じになってます。
とりあえず動くだけになってしまっているかも、
出来上がるものについて理解していなければ難しいなと思いました。

まだまだ未熟者だなと思い知らされました。

#![allow(non_snake_case)]
extern crate rand;

use std::{thread, time};
use rand::Rng;

const COUNT: u32 = 20;
const PIONEER: u32 = 100;

#[derive(Copy, Clone, PartialEq)]
enum Status{
    Live,
    Death,
}

struct Field{
    cells: [[Status; COUNT as usize]; COUNT as usize]
}

impl Field {
    fn new() -> Field{
        Field{
            cells: [[Status::Live; COUNT as usize]; COUNT as usize]
        }
    }

    fn randomBirthday(&mut self){
        let mut rnd = rand::thread_rng();
        for _ in 0..PIONEER {
            self.cells[rnd.gen_range(0,COUNT) as usize][rnd.gen_range(0,COUNT) as usize] = Status::Live;
        }
    }

    fn decideLife(&mut self, x: isize, y: isize){
        let neighbor_count = self._getNeighborsCount(x, y);
        if self._isExist(x, y) {
            if self._isUnderPopulation(neighbor_count) || self._isOverPopulation(neighbor_count){
                self._deathCell(x as usize, y as usize);
            }
        }else{
            if self._isJustPopulation(neighbor_count){
                self._liveCell(x as usize, y as usize);
            }
        }
    }

    fn write(&self){
        for y in 0..COUNT {
            for x in 0..COUNT {
                if self.cells[y as usize][x as usize] == Status::Live {
                    print!("o  ");
                }else{
                    print!("_  ");
                }
            }
            println!("\n");
        }
        println!("\n");
    }

    fn _liveCell(&mut self, x: usize, y: usize){
        self.cells[y][x] = Status::Live;
    }
    fn _deathCell(&mut self, x: usize, y: usize){
        self.cells[y][x] = Status::Death;
    }
    fn _getNeighborsCount(&self, x: isize, y: isize) -> i32 {
        let mut result = 0;
        if self._isNotOutOfField(x-1) && self._isNotOutOfField(y-1) && self._isExist(x-1, y-1){ result += 1 }
        if self._isNotOutOfField(y-1) && self._isExist(x, y-1){ result += 1 }
        if self._isNotOutOfField(x+1) && self._isNotOutOfField(y-1) && self._isExist(x+1, y-1){ result += 1}
        if self._isNotOutOfField(x-1) && self._isExist(x-1, y){ result += 1}
        if self._isNotOutOfField(x+1) && self._isExist(x+1, y){ result += 1}
        if self._isNotOutOfField(x-1) && self._isNotOutOfField(y+1) && self._isExist(x-1, y+1){ result += 1}
        if self._isNotOutOfField(y+1) && self._isExist(x, y+1){ result += 1}
        if self._isNotOutOfField(x+1) && self._isNotOutOfField(y+1) && self._isExist(x+1, y+1){ result += 1}
        return result
    }
    fn _isUnderPopulation(&self, count: i32) -> bool {
        count == 0 || count == 1
    }
    fn _isOverPopulation(&self, count: i32) -> bool {
        count >= 4
    }
    fn _isJustPopulation(&self, count: i32) -> bool {
        count == 3
    }
    fn _isExist(&self, x: isize, y: isize) -> bool {
        self.cells[y as usize][x as usize] == Status::Live
    }
    fn _isNotOutOfField(&self, num: isize) -> bool {
        self._isOver0(num) && self._isUnderCount(num)
    }
    fn _isOver0(&self, num: isize) -> bool {
        num >= 0
    }
    fn _isUnderCount(&self, num: isize) -> bool {
        num < COUNT as isize
    }
}

fn main() {
    println!("Hello, world!");
    let mut field = Field::new();
    field.randomBirthday();
    field.write();

    loop {
        for y in 0..COUNT as usize{
            for x in 0..COUNT {
                field.decideLife(x as isize, y as isize);
            }
        }
        field.write();

        thread::sleep(time::Duration::from_millis(100));
    }
}

難しいですけどとても面白いですね。
かけるようになれればレベルアップできそうです。
がんばります。。。

slackで出来るテトリス作りました。

slackでテトリス作って見ました。

遅いけど、
まぁまぁ楽しめるかもしれません。

github.com

写真載せようと思って
起動して見たら、Invalid Oauthと出てしまったので、
Debug時にアクセスしすぎたかもしれません。
slackさんすみません。。。

自分でやって見てください。

これを機にgem化とかして見たいです。