Sunday, May 31, 2009

9月まで

9月の結婚式まで、なんだか忙しい日が続きそうです。
でも、階段を上がって息がちょっと上がった感じ。
立ち止まって上を見れば、新生活の切符を切る日が近づいています。
周りを見れば、見通しがいい、景色のいい場所まで登ってきました。
横に見れば、いるのは紛れもなく、かけがえのない人です。
あとは前を見るだけです。

Sunday, May 17, 2009

C#でxiを解く方法


趣味の延長で、xiを解くC#プログラムを作成しました。

趣味で囲碁をやり始めてますが、
それとは別に、もう半年ほどやっているパズルが
xiと呼ばれるアクションパズルです。
さいころを転がして、同じ目のさいころを目の数だけくっつけると
そのさいころを消すことができる、というルールしかないパズルです。

シンプルなルールなので、全数検索的な解法探索プログラムは
・さいころを1回転がすアクションの関数
・くっついたさいころの目が一緒か判定する関数
・解法を探すという再帰的な関数
・解法という再帰的なオブジェクト
を作ればよいです。

ただ作るのは面白くないので、オブジェクト指向のC#に挑戦しました。
LIB6 stage3に挑戦させた結果、ちゃんと解法が3つ出ました。

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
int DICEMAX = 100;
AnswerList al1, al2;
Answer a1;
Move m;
Map map, map2;
static Dir[] dirs;

public Form1()
{
InitializeComponent();
this.init();
}
public void init() {
//Graphicsオブジェクトの作成
dirs = new Dir[] { Dir.up, Dir.right, Dir.down, Dir.left };
m = new Move(1,Dir.up);
a1 = new Answer(m);
al1 = new AnswerList();
al2 = new AnswerList();
map = new Map();
map2 = new Map();

map.AddDice(new Dice(new Pos(1, 0), 4, 5, 6));
map.AddDice(new Dice(new Pos(0, 1), 6, 2, 4));
map.AddDice(new Dice(new Pos(1, 1), 5, 1, 3));
map.AddDice(new Dice(new Pos(2, 1), 4, 5, 6));
map.AddDice(new Dice(new Pos(1, 2), 3, 2, 6));
map.AddDice(new Dice(new Pos(0, 3), 6, 2, 4));
map2.AddDice(new Dice(new Pos(0, 0), 6, 1, 3));
map2.AddDice(new Dice(new Pos(1, 0), 6, 1, 3));
map2.AddDice(new Dice(new Pos(0, 1), 6, 1, 3));
map2.AddDice(new Dice(new Pos(0, 2), 6, 1, 3));
map2.AddDice(new Dice(new Pos(1, 2), 6, 1, 3));
map2.AddDice(new Dice(new Pos(0, 3), 6, 1, 3));
// map.AddDice(new Dice(new Pos(
// map.ApplyMove(new Move(0, Dir.down));
// al1.Print();
this.label1.Text = al1.GetValue();
}

private void button1_Click(object sender, EventArgs e)
{
Console.Write(map.Finished());
al1 = Search(5, map, map2, 2);
this.label2.Text = al1.GetValue();
Graphics g = pictureBox1.CreateGraphics();
//Penオブジェクトの作成(幅1の黒色)
//(この場合はPenを作成せずに、Pens.Blackを使っても良い)
Pen p = new Pen(Color.Black, 1);
//(10,20,100,80)の長方形を描く
g.DrawRectangle(p, 10, 20, 100, 80);
//リソースを開放する
p.Dispose();
g.Dispose();
}

public class AnswerList : List
{
public AnswerList() {
}
public void Extend(Move m) {
foreach (Answer ans in this) {
ans.Extend(m);
}
}
public void New(Move m) {
this.Add(new Answer(m));
}
public void Plus(AnswerList o) {
foreach (Answer ans in o) {
this.Add(ans);
}
}
public void Print() {
foreach (Answer ans in this)
{
Console.Write("{\n");
ans.Print();
Console.Write("}\n");
}
}
public String GetValue() {
String str_ = "";
foreach(Answer ans in this) {
str_ += ans.GetValue();
}
return str_;
}
}

public class Answer : List
{
public Answer(Move m) {
this.Add(m);
}
public void Extend(Move m) {
this.Insert(0,m);
}
public void Print() {
foreach (Move move in this)
{
Console.Write("{\n");
move.Print();
Console.Write("}\n");
}
}
public String GetValue() {
String str_ = "";
foreach (Move move in this)
{
str_ += move.GetValue();
}
str_ += "(end)\n";
return str_;
}
}

public class Move : Object
{
public int dice_;
public Dir dir_;

public Move(int dice, Dir dir) {
dice_ = dice;
dir_ = dir;
}
public void Print() {
Console.Write("{0},{1}\n", this.dice_, this.dir_);
}
public String GetValue() {
return String.Format("({0},{1})->", this.dice_, this.dir_);
}
}

public class Map : List {
int xmax_;
int ymax_;
Dictionary AddressDict;
public Map()
{
xmax_ = ymax_ = 4;
AddressDict = new Dictionary();
}
public bool Equals(Map o) {
int tmpdice;
foreach(Pos pos in AddressDict.Keys) {
if(!o.AddressDict.TryGetValue(pos, out tmpdice)) {
return false;
}
if(!o[tmpdice].Equals(this[AddressDict[pos]])) {
return false;
}
}
return true;
}
public bool AddDice(Dice dice)
{
if (FeasiblePos(dice.pos_))
{
this.Add(dice);
AddressDict.Add(dice.pos_, this.Count - 1);
return true;
}
return false;
}
public void Plus(Map o)
{
foreach (Dice dice in o)
{
this.Add(new Dice(dice));
}
foreach (Pos pos in o.AddressDict.Keys)
{
this.AddressDict.Add(pos, o.AddressDict[pos]);
}
xmax_ = o.xmax_;
ymax_ = o.ymax_;
}

public bool FeasiblePos(Pos pos)
{
return pos.x_ >= 0 && pos.y_ >= 0 && pos.x_ < xmax_ && pos.y_ < ymax_ && !AddressDict.ContainsKey(pos);
}

public bool Finished()
{
List checklist = new List();
List tmpdicearound = new List();
Dictionary facecount = new Dictionary();
int tmpcount = 0, tmpface = 0;
for(int i = 0; i < this.Count; i++)
checklist.Add(i);
while (checklist.Any())
{
tmpdicearound.Clear();
DiceAround(checklist.First(),tmpdicearound);
foreach (int dice in tmpdicearound)
{
tmpface = this[dice].GetFace();
if (facecount.ContainsKey(tmpface))
facecount[tmpface]++;
else
facecount.Add(tmpface, 1);
checklist.Remove(dice);
}
foreach (int face in facecount.Keys)
{
if (facecount[face] < face)
{
return false;
}
}
}
return true;
}
public bool ApplyMove(Move move)
{
bool outbool = true;
Pos nowpos, nextpos;
nowpos = this[move.dice_].pos_;
nextpos = nowpos.AddDir(move.dir_);
if (outbool = FeasiblePos(nextpos))
{
this[move.dice_].Turn(move.dir_);
this.AddressDict.Remove(nowpos);
this.AddressDict.Add(nextpos, move.dice_);
}
return outbool;
}
public bool DiceAround(int dice, List list)
{
Pos tmppos;
int tmpdice;
bool outbool = true;
if (dice >= this.Count)
return false;
if (!list.Contains(dice))
list.Add(dice);
else
return true;
foreach (Dir dir in Form1.dirs)
{
tmppos = this[dice].pos_.AddDir(dir);
if (AddressDict.TryGetValue(tmppos, out tmpdice))
{
outbool &= DiceAround(tmpdice, list);
}
}
return outbool;
// PosToDice(
}
// public Dice
}

public class Dice : Object {
int[] face_ = {0,1,2,3,4,5};
public Pos pos_;

public Dice() {
pos_ = new Pos();
}
public Dice(Pos pos, int i1, int i2, int i3)
{
pos_ = new Pos(pos);
face_[0] = i1;
face_[1] = i2;
face_[2] = i3;
face_[3] = 7 - i3;
face_[4] = 7 - i2;
face_[5] = 7 - i1;
}
public Dice(Dice dice)
{
pos_ = new Pos(dice.pos_);
dice.face_.CopyTo(face_, 0);
}
public int GetFace() {
return face_[0];
}
public override bool Equals(Object obj)
{
if (obj == null || GetType() != obj.GetType()) return false;
Dice dice = (Dice)obj;
bool outbool = this.pos_.Equals(dice.pos_);
foreach(int a in new int[]{0}) {
outbool &= (this.face_[a] == dice.face_[a]);
}
return outbool;
}

public override int GetHashCode()
{
return face_[0] ^ face_[1] ^ face_[2] ^ face_[3] ^ face_[4] ^ face_[5];
}
public void Turn(Dir dir)
{
int tmp;
switch (dir)
{
case Dir.up:
tmp = face_[0];
face_[0] = face_[1];
face_[1] = face_[5];
face_[5] = face_[4];
face_[4] = tmp;
break;
case Dir.down:
tmp = face_[0];
face_[0] = face_[4];
face_[4] = face_[5];
face_[5] = face_[1];
face_[1] = tmp;
break;
case Dir.right:
tmp = face_[0];
face_[0] = face_[3];
face_[3] = face_[5];
face_[5] = face_[2];
face_[2] = tmp;
break;
case Dir.left:
tmp = face_[0];
face_[0] = face_[2];
face_[2] = face_[5];
face_[5] = face_[3];
face_[3] = tmp;
break;
}
pos_ = new Pos(pos_.AddDir(dir));
return;
}
}

public class Pos : Object {
public int x_;
public int y_;
public Pos() {
}
public Pos(int i1, int i2)
{
Set(i1, i2);
}
public Pos(Pos pos)
{
x_ = pos.x_;
y_ = pos.y_;
}

public void Set(int i1, int i2) {
x_ = i1;
y_ = i2;
}
public override bool Equals(Object obj)
{
if (obj == null || GetType() != obj.GetType()) return false;
Pos pos = (Pos)obj;
return (this.x_==pos.x_)&&(this.y_==pos.y_);
}

public override int GetHashCode()
{
return x_ ^ y_;
}

public Pos AddDir(Dir dir)
{
switch (dir)
{
case Dir.up:
return new Pos(x_, y_ + 1);
case Dir.down:
return new Pos(x_, y_ - 1);
case Dir.right:
return new Pos(x_ + 1, y_);
case Dir.left:
return new Pos(x_ - 1, y_);
}
return null;
}
}

public AnswerList Search(int limit, Map map, Map lastmap, int dice_) {
AnswerList outList = new AnswerList();
AnswerList tmpList = new AnswerList();
Move tmpmove;
Map tmpmap;
List dicelist = new List();
map.DiceAround(dice_, dicelist);
foreach (int neighbor in dicelist)
{
foreach (Dir dir in dirs)
{
tmpmap = new Map();
tmpmap.Plus(map);
if(tmpmap.ApplyMove(tmpmove = new Move(neighbor, dir))) {
// if(tmpmap.Equals(lastmap)) {
if(tmpmap.Finished()) {
// Console.Write(tmpmap.Finished());
outList.Add(new Answer(tmpmove));
return outList;
}
if(limit == 1)
continue;
// if((tmpList = Search(limit - 1, tmpmap, lastmap, neighbor)) != null)
tmpList = Search(limit - 1, tmpmap, lastmap, neighbor);
tmpList.Extend(tmpmove);
outList.Plus(tmpList);
}
}
}
return outList;
}

public enum Dir { up, right, down, left }
}
}

Tuesday, May 12, 2009

囲碁にはまっています I -igowin-

igowinという囲碁ソフトウェアがあります。
フリーでダウンロードでき、そこそこのAIを搭載しているところが売りのようです。
そういうことから、初心者におすすめだそうです。
Igowin software for download
ubcgoclub / Beginners Training Schedule

ということで2週間ちょいちょい遊んで、4kyuというレベルをクリアできました。
4kyuでは、AIに2子置かせて9路盤で戦います。
(AIは最初に対面の三三に2子置です。)
かなり無茶をしながら、勝つことができました。
上記囲碁上達法では、これ以上igowinは無用らしいので、別の囲碁ソフトウェアで頭を鍛えることとします。
とりあえず次はGnuGoの予定。

Tuesday, May 05, 2009

英語合宿に使った本 1: 1100 words you need to know

Amazon.com: 1100 Words You Need to Know: Murray Bromberg, Melvin Gordon: Books

語彙力の強化にお薦めの本。
今、英語合宿と題してGWに引き篭もり、これを使って勉強中です。
$10にしては充実の1100語で、一語あたり1円となります(笑)

【内容】
20行程度の例文に5つの新語が入っています。
週ごとに4つの例文を読めるように準備されています。
これを1年、50週続けます。
200程度の例文で1100語をカバーするわけです。
ネイティブの高校生や大学生が勉強するためのもので、
例文は難しすぎません。でも簡単でもないです。
Wall Street Journalなどの新聞よりもちょっと簡単、と言った程度です。

【いいところ】
索引、例文サマリーあります。
前に学習した単語が後でも多用されていて復習になります。
(しかも、前に出た単語は印がついている)

【悪いところ】
プランが長い・・・一回頓挫しました。でも再挑戦中。
しかも、結構関係ない単語がばらばらに出てくる。
etymologyかなんかでまとめてくれるとうれしいんだが・・・