Home > Archives > 2008-02

2008-02

AS3はじめました

以前、3D-MindMapみたいなソフトを作ろうと思ってJava3Dをかじったのですが、現在はAPIが標準ライブラリに含まれていないので、制作物の配布がやりずらそうだなぁと、それじゃDirectXかOpneGLあたりでゴリゴリ書こうかなと当初は思っていました。

しかし、AS3になって実行速度がある程度改善されたのと、文法がすっきり(Javaに似てる)しているのでとっつき易そうだなと思い、AS3を始めました。それに、ブラウザというある種の共通の環境で動作すのが良いかと考えました。

さて手始めに早速一つ、マウスでドラックしている間、線を描くFlashです。

Continue reading

C#でキッチンタイマーを作ろう

カウントダウンタイマーとも言うのかな。
さて、今回学んだことは、

  • X秒からh:m:s形式での表示。
  • タイマースレッドの利用。

かな。
タイマーイベント毎に重い処理を行うと表示時間と実時間のずれが大きくなるので注意。そういった場合はイベント発生間隔を長めに取ってみる。

プログラムの実行結果

起動時

キッチンタイマー初期画面 by yukun

実行時

キッチンタイマーのカウント時 by yukun

ちなみにボタンをロックするにはボタンインスタンスのEnabledプロパティにfalseを代入します(ロック解除はture)。

例(butstartはボタンクラスのインスタンス変数):

butstart.Enabled = false; // スタートボタンをロック(スタートが押されたら場合)

ソースコード

FormTimer.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
/**
 * キッチンタイマー
 * Web page: http://www.yukun.info/
 * license GPLv2
 */
namespace Sample
{
  public partial class FormTimer : Form
  {
    public FormTimer()
    {
      InitializeComponent();
      // マウスポインタの場所に表示
      this.DesktopLocation = new Point(System.Windows.Forms.Cursor.Position.X,
        System.Windows.Forms.Cursor.Position.Y);
    }
    int sec = 0; // 計測時間

    private void viewtime()
    {
      stLabel1.Text = "" + sec / 36000 % 10 + sec / 3600 % 10 +
                     ":" + sec / 600 % 6 + sec / 60 % 10 +
                     ":" + sec / 10 % 6 + sec % 10;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
      sec--;
      if (0 == sec)
      {
        sttimer.Enabled = false;
        System.Media.SystemSounds.Beep.Play();
        this.Activate();
      }
      viewtime();
    }

    private void butsec_Click(object sender, EventArgs e)
    {
      sec += 10;
      viewtime();
    }

    private void butmin_Click(object sender, EventArgs e)
    {
      sec += 60;
      viewtime();
    }

    private void buthour_Click(object sender, EventArgs e)
    {
      sec += 3600;
      if (sec >= 360000) sec = 0;
      viewtime();
    }

    private void butstart_Click(object sender, EventArgs e)
    {
      if (0 == sec) return;
      sttimer.Enabled = true;
      this.butstop.Enabled = true;
      this.butstart.Enabled = false;
      this.buthour.Enabled = false;
      this.butmin.Enabled = false;
      this.butsec.Enabled = false;
      this.butreset.Enabled = false;
    }

    private void butstop_Click(object sender, EventArgs e)
    {
      sttimer.Enabled = false;
      this.butstop.Enabled = false;
      this.butstart.Enabled = true;
      this.buthour.Enabled = true;
      this.butmin.Enabled = true;
      this.butsec.Enabled = true;
      this.butreset.Enabled = true;
    }

    private void butreset_Click(object sender, EventArgs e)
    {
      stLabel1.Text = "00:00:00";
      sec = 0;
    }

    private void 常に手前に表示ToolStripMenuItem_Click(object sender, EventArgs e)
    {
      //クリックするごとにこのフォームを常に手前または解除します。
      this.TopMost = !this.TopMost;
    }
  }
}

FormTimer.Designer.cs

namespace Sample
{
  partial class FormTimer
  {
    /// <summary>
    /// 必要なデザイナ変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region Windows フォーム デザイナで生成されたコード

    /// <summary>
    /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディタで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      this.components = new System.ComponentModel.Container();
      this.sttimer = new System.Windows.Forms.Timer(this.components);
      this.buthour = new System.Windows.Forms.Button();
      this.butmin = new System.Windows.Forms.Button();
      this.butsec = new System.Windows.Forms.Button();
      this.butstart = new System.Windows.Forms.Button();
      this.stLabel1 = new System.Windows.Forms.Label();
      this.butstop = new System.Windows.Forms.Button();
      this.butreset = new System.Windows.Forms.Button();
      this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
      this.常に手前に表示ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
      this.contextMenuStrip1.SuspendLayout();
      this.SuspendLayout();
      //
      // sttimer
      //
      this.sttimer.Interval = 1000;
      this.sttimer.Tick += new System.EventHandler(this.timer1_Tick);
      //
      // buthour
      //
      this.buthour.Location = new System.Drawing.Point(6, 66);
      this.buthour.Name = "buthour";
      this.buthour.Size = new System.Drawing.Size(50, 23);
      this.buthour.TabIndex = 0;
      this.buthour.Text = "HOUR";
      this.buthour.UseVisualStyleBackColor = true;
      this.buthour.Click += new System.EventHandler(this.buthour_Click);
      //
      // butmin
      //
      this.butmin.Location = new System.Drawing.Point(62, 66);
      this.butmin.Name = "butmin";
      this.butmin.Size = new System.Drawing.Size(50, 23);
      this.butmin.TabIndex = 1;
      this.butmin.Text = "MIN";
      this.butmin.UseVisualStyleBackColor = true;
      this.butmin.Click += new System.EventHandler(this.butmin_Click);
      //
      // butsec
      //
      this.butsec.Location = new System.Drawing.Point(118, 66);
      this.butsec.Name = "butsec";
      this.butsec.Size = new System.Drawing.Size(50, 23);
      this.butsec.TabIndex = 2;
      this.butsec.Text = "SEC";
      this.butsec.UseVisualStyleBackColor = true;
      this.butsec.Click += new System.EventHandler(this.butsec_Click);
      //
      // butstart
      //
      this.butstart.Location = new System.Drawing.Point(6, 100);
      this.butstart.Name = "butstart";
      this.butstart.Size = new System.Drawing.Size(50, 23);
      this.butstart.TabIndex = 3;
      this.butstart.Text = "スタート";
      this.butstart.UseVisualStyleBackColor = true;
      this.butstart.Click += new System.EventHandler(this.butstart_Click);
      //
      // stLabel1
      //
      this.stLabel1.AutoSize = true;
      this.stLabel1.BackColor = System.Drawing.SystemColors.Control;
      this.stLabel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
      this.stLabel1.Font = new System.Drawing.Font("Times New Roman", 30F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
      this.stLabel1.Location = new System.Drawing.Point(6, 9);
      this.stLabel1.Name = "stLabel1";
      this.stLabel1.Size = new System.Drawing.Size(163, 42);
      this.stLabel1.TabIndex = 4;
      this.stLabel1.Text = "00:00:00";
      //
      // butstop
      //
      this.butstop.Location = new System.Drawing.Point(62, 100);
      this.butstop.Name = "butstop";
      this.butstop.Size = new System.Drawing.Size(50, 23);
      this.butstop.TabIndex = 5;
      this.butstop.Text = "ストップ";
      this.butstop.UseVisualStyleBackColor = true;
      this.butstop.Click += new System.EventHandler(this.butstop_Click);
      //
      // butreset
      //
      this.butreset.Location = new System.Drawing.Point(118, 100);
      this.butreset.Name = "butreset";
      this.butreset.Size = new System.Drawing.Size(50, 23);
      this.butreset.TabIndex = 6;
      this.butreset.Text = "リセット";
      this.butreset.UseVisualStyleBackColor = true;
      this.butreset.Click += new System.EventHandler(this.butreset_Click);
      //
      // contextMenuStrip1
      //
      this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
      this.常に手前に表示ToolStripMenuItem});
      this.contextMenuStrip1.Name = "contextMenuStrip1";
      this.contextMenuStrip1.Size = new System.Drawing.Size(171, 26);
      //
      // 常に手前に表示ToolStripMenuItem
      //
      this.常に手前に表示ToolStripMenuItem.CheckOnClick = true;
      this.常に手前に表示ToolStripMenuItem.Name = "常に手前に表示ToolStripMenuItem";
      this.常に手前に表示ToolStripMenuItem.Size = new System.Drawing.Size(170, 22);
      this.常に手前に表示ToolStripMenuItem.Text = "常に Top に表示する";
      this.常に手前に表示ToolStripMenuItem.Click += new System.EventHandler(this.常に手前に表示ToolStripMenuItem_Click);
      //
      // FormTimer
      //
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
      this.ClientSize = new System.Drawing.Size(180, 129);
      this.ContextMenuStrip = this.contextMenuStrip1;
      this.Controls.Add(this.butreset);
      this.Controls.Add(this.butstop);
      this.Controls.Add(this.stLabel1);
      this.Controls.Add(this.butstart);
      this.Controls.Add(this.butsec);
      this.Controls.Add(this.butmin);
      this.Controls.Add(this.buthour);
      this.Name = "FormTimer";
      this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
      this.Text = "タイマー";
      this.contextMenuStrip1.ResumeLayout(false);
      this.ResumeLayout(false);
      this.PerformLayout();

    }

    #endregion

    private System.Windows.Forms.Button buthour;
    private System.Windows.Forms.Button butmin;
    private System.Windows.Forms.Button butsec;
    private System.Windows.Forms.Button butstart;
    private System.Windows.Forms.Label stLabel1;
    private System.Windows.Forms.Button butstop;
    private System.Windows.Forms.Button butreset;
    private System.Windows.Forms.Timer sttimer;
    private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
    private System.Windows.Forms.ToolStripMenuItem 常に手前に表示ToolStripMenuItem;
  }
}

3種類の括弧の対応をチェックするC言語プログラム

先日勉強会でこの辺のテーマを取り上げたので、字句解析や構文解析(の一部)とスタックの復習も兼ねて作成(required for 1h+)。

実装のポイント

  • 閉じ括弧の有無の判定は、ファイルの終端が読み終わった後。
  • 開き括弧の判定は、閉じ括弧を読み込んだ際に行い、スタックの最上位に対応する開き括弧があるか否かで。
  • 入れ子の(または再帰的な)構造で、どの深さにスレッドがいるか調べるにはスタックを用いる。

ソースコード(C言語) valid_pare.c

#include <stdio.h>
#include <stdlib.h>

const int MAXSIZE = 128; // スタックサイズ(静的)
// スタックするデータ構造(Cell)
typedef struct brackets Brackets;
struct brackets {
  int kind; // 括弧の種類
  int line; // 位置:行
  int pos; // 位置:列
};
Brackets stack[128];
int pnt;

Brackets pop(void)
{
  if (pnt < = 0) {
    printf("error:stack empty.\n");
    exit(1);
  }
  pnt--;
  return stack[pnt];
}
void push(Brackets b)
{
  if (pnt >= MAXSIZE) {
    printf("error:stack fullness.\n");
    exit(1);
  }
  stack[pnt] = b;
  pnt++;
}
// stackが空(1)か否(0)か
int empty(void)
{
  return (pnt == 0) ? 1 : 0;
}
// スタックの最上位の文字種を返す
int peek()
{
  return stack[pnt-1].kind;
}
// 括弧の判別
int kind(int ch)
{
  int code;
  switch (ch) {
  case '(':
    code = 1;
    break;
  case ')':
    code = 2;
    break;
  case '{':
    code = 3;
    break;
  case '}':
    code = 4;
    break;
  case '[':
    code = 5;
    break;
  case ']':
    code = 6;
    break;
  default:
    code = 0; // 括弧以外の文字
    break;
  }
  return code;
}

int main()
{
  int ch;
  FILE *fp;
  char fname[64]; // ファイル名
  int k; // 文字の種類
  int line = 1, pos = 0;
  Brackets kakko, temp;

  pnt = 0; // スタックポインタ(GV)の初期化
  printf("Filename:");
  scanf("%62s", fname);
  if ((fp = fopen(fname, "r")) == NULL) {
    printf("\aCan't be opened.\n");
    exit(1);
  }
  //printf("%d行目\n", line);
  // ファイルから一文字ずつ読む
  while ((ch = fgetc(fp)) != EOF) {
    //putchar(ch);
    if (ch == '\n') {
      line++; pos=0;
      //printf("%d行目\n", line);
      continue;
    }
    pos++;
    //printf("%d", pos);
    k = kind(ch);
    if (k > 0) { // 文字が括弧の場合
      if (k % 2) { // 開き括弧の場合
        kakko.kind = k;
        kakko.line = line;
        kakko.pos  = pos;
        push(kakko);
      } else if (!empty() && (k == peek()+1)) {
        temp = pop(); // 対応する閉じ括弧があった
      } else {
        printf("対応する開き括弧がない");
        printf("(%d行目の%d文字目)。\n", line, pos);
      }
    }
  }
  puts("テキスト終端");
  fclose(fp);
  if (!empty()) {
    printf("対応する閉じ括弧がない。\n");
    while (!empty()) {
      temp = pop();
      printf("%d行目の%d文字目。\n", temp.line, temp.pos);
    }
  }
  return 0;
}

使用したText

(1+2)
ac)c
((3+6)ge))
(([y)
ij])(k
{5/3}

実行結果

D:\parentheses>gcc valid_pare.c
D:\parentheses>a.exe
Filename:pare.txt
対応する開き括弧がない(2行目の3文字目)。
対応する開き括弧がない(3行目の10文字目)。
対応する開き括弧がない(4行目の5文字目)。
テキスト終端
対応する閉じ括弧がない。
5行目の5文字目。
4行目の1文字目。
D:\parentheses>

改良するなら

  • 関数を他のファイルに分けて、main側でインクルードする。
  • スタック領域を動的に割り当てる。(Brackets *)emalloc(sizeof(Brackets))かな。
  • スタック配列を伸縮性のある構造・操作関数で実装する。
  • 結果の表示をコンパイラのエラー出力っぽくする。該当箇所に「^」をマーク。
  • 他の言語で実装してみる(OOPを用いて等等)。
  • 字句・構文解析のオープンソースを参考にする。

こういった小さなものを作りつつ、OOPのパターンに基づいて拡張性を考慮する今日この頃。

Webページから指定したタグの要素を抜き出すRuby関数

単一のWebページから抜き出した複数の要素を配列に格納して返します。
以下の例はaタグの要素(エレメント)を抽出した場合です。

Rubyコード

require 'net/http'
require 'kconv'

def parse_array(string, beg_tag, close_tag)
  array = Array.new
  string.scan(/#{beg_tag}(.*?)#{close_tag}/sm) { |matched|
    #puts matched
    array = array | matched
  }
  return array
end

Net::HTTP.version_1_2
Net::HTTP.start('b.hatena.ne.jp', 80) {|http|
  response = http.get('/hotentry/')
  str = Kconv.tosjis(response.body)
  a_tag_array = parse_array(str, "<a href=", "<\/a>" )
  puts a_tag_array
}

学んだこと

  • Net::HTTP.startメソッドをブロックを用いて呼び出すことによって、ブロックの間だけセッションを開いて接続し、ブロック終了とともに自動的にセッションを閉じる。Rubyに慣れてもJavaやCでの手続きを意識しておくこと。
  • 配列の結合には和集合(演算子は「|」)を用いた。この場合、重複する要素は1つとして数えられる。別々に数えたい場合は「+」演算子を用いる。
  • String#scanメソッドはブロックで用いるとブロック変数にマッチした部分を格納する。その際、正規表現の中で「()」が用いられると、()内の部分を配列にして返す。今回は別に配列にする必要はなかったかも。

参考サイト

Web サーバからドキュメントを得る - Rubyist Magazine - 標準添付ライブラリ紹介 【第 7 回】 net/http

タグの中の要素を抜き出すRuby関数

ライブラリを使えば簡単ですが、正規表現の学習の為に。

ソースコード

def return_between(unporsed, start, termi)
  unporsed =~ /#{start}(.*?)#{termi}/
  return $1
end

str = "<title>Trump Code</title>"
start = "<title>"
termi = "</title>"

puts return_between(str, start, termi)
#=> Trump Code

ここで学んだことは、正規表現の規則中に変数を用いる際は#{var_str}と表記すること。

Page 1 of 212

Home > Archives > 2008-02

バックナンバー
最近のコメント
最近のトラックバック
メタ情報

Return to page top