Sunday, July 26, 2009

JavaFX - Peg Game.

JavaFX is a technology from SUN ( recently taken over by Oracle ) that competes against Adobe Flash and Microsoft Silverlight.

This article shows how to build a simple JavaFX program to play the 'Peg Game'.

The Peg game is played with a triangular piece of board with 15 holes in it. One hole (usually the top) is left open and golf tees are placed into the other 14. The objective is to hop over the pegs, removing the hopped peg, and in doing so remove all but one peg from the game.

Here it is in action: http://turnbasedgames.appspot.com/lastblock/Last_Block_Standing.html



To create this game I have four files:

Main.fx
TriangleBase.fx
GameSquare.fx
Util.java

Main.fx consists of:

package javafxapplication1;

import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafxapplication1.TriangleBase;


/**
* @author Lars Vogel
*/
Stage {
var rect: Rectangle;
var circ: Circle;
title: "Last Block Standing"
scene: Scene {
width: 500
height: 500
var myString = "Last Block Standing"
var gameInstance: TriangleBase = new TriangleBase;
content: [
gameInstance,
Rectangle {
x: 50,
y: 300
width: 50,
height: 15
arcHeight: 2
arcWidth: 2
stroke: Color.BLACK
strokeWidth: 2
fill: LinearGradient {
startX: 0.0
startY: 0.0
endX: 0.0
endY: 1.0
stops: [
Stop {
color: Color.ORANGE
offset: 0.0
},
Stop {
color: Color.DARKRED
offset: 0.3
},
Stop {
color: Color.ORANGE
offset: 1.0
},
]
}
onMouseClicked: function(me) {
gameInstance.restart();
}
}
Text {
fill: Color.WHITE
font: Font {
name: "Arial Bold"
size: 12
}
x: 55,
y: 315
content: "Restart"
}
]
}
}

Triangle Base:
/*
* TriangleBase.fx
*
* Created on Jul 23, 2009, 10:55:02 PM
*/

package javafxapplication1;

import javafx.scene.control.Control;
import javafx.scene.Group;
import javafx.scene.Node;

/**
* @author avalanche
*/

public class TriangleBase extends Control {
public override function create(): Node {
return group;
}

var group: Group =
Group {
content: [
]
};
public function buildContent() {
insert GameSquare{ SquareId:1 x1:50 y1:0 hasTee:false} into group.content;
insert GameSquare{ SquareId:2 x1:40 y1:20} into group.content;
insert GameSquare{ SquareId:3 x1:60 y1:20} into group.content;
insert GameSquare{ SquareId:4 x1:30 y1:40} into group.content;
insert GameSquare{ SquareId:5 x1:50 y1:40} into group.content;
insert GameSquare{ SquareId:6 x1:70 y1:40} into group.content;
insert GameSquare{ SquareId:7 x1:20 y1:60} into group.content;
insert GameSquare{ SquareId:8 x1:40 y1:60} into group.content;
insert GameSquare{ SquareId:9 x1:60 y1:60} into group.content;
insert GameSquare{ SquareId:10 x1:80 y1:60} into group.content;
insert GameSquare{ SquareId:11 x1:10 y1:80} into group.content;
insert GameSquare{ SquareId:12 x1:30 y1:80} into group.content;
insert GameSquare{ SquareId:13 x1:50 y1:80} into group.content;
insert GameSquare{ SquareId:14 x1:70 y1:80} into group.content;
insert GameSquare{ SquareId:15 x1:90 y1:80} into group.content;
}

public function restart() {
delete group.content;
buildContent();
println("performing restart");
}
postinit{
buildContent();
}

}

GameSquare:
/*
* Node.fx
*
* Created on Jul 23, 2009, 11:12:07 PM
*/

package javafxapplication1;

import javafx.scene.control.Control;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafxapplication1.Util;
import java.util.HashMap;

var clickedSquare: GameSquare= null;
var gameSquareMap = new HashMap();

public class GameSquare extends Control {
public var SquareId: Integer;
public var squareColor: Color = Color.GREEN;
public var x1: Number;
public var y1: Number;
public var hasTee: Boolean = true;

var rect: Rectangle =
Rectangle{

fill: bind squareColor;

height: (20 * 2)
width: (20 * 2 )
translateX: (x1 * 2 )
translateY: (y1 * 2)
stroke: Color.BLACK;
onMouseClicked: function(me){


// first click, and I have a tee
if (clickedSquare == null and this.hasTee == true) {
println("setting clickedsquare");
clickedSquare = this;
clickedSquare.setIsClicked(true)


// second click, and I don't have a tee
}else if(this.hasTee == false and clickedSquare != null) {
// Find square we jumped over.
var hoppedNode = Util.getHoppedNode(clickedSquare.SquareId, this.SquareId);
if (hoppedNode != -1 ) {
var hoppedSquare = gameSquareMap.get(hoppedNode) as GameSquare;
if (hoppedSquare.hasTee) {
// hopped square is now empty
hoppedSquare.setHasTee(false);
this.setHasTee(true);
clickedSquare.setHasTee(false);
}
}
clickedSquare.setIsClicked(false);
clickedSquare = null;
} else {
//invalid remove marker for first click so user can try again.
clickedSquare.setIsClicked(false);
clickedSquare = null;
}

}
}


public override function create(): Rectangle {
return rect;
}
function setIsClicked(arg:Boolean) {
if (arg==true) {
squareColor = Color.BROWN;
}
else {
setHasTee(hasTee); //set to proper color;
}
}

function setHasTee(arg:Boolean) {
hasTee = arg;
if (hasTee == true) {
squareColor = Color.GREEN;
} else {
squareColor = Color.RED;
}
}

postinit {
this.setHasTee(hasTee);
gameSquareMap.put(SquareId, this);
}
}

Util.java

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package javafxapplication1;

import java.util.HashMap;
import java.util.Map;

/**
*
* @author avalanche
*/
public class Util {
static Map connections = new HashMap();
static {
connections.put("1,4", 2);
connections.put("1,6",3);
connections.put("2,7",4);
connections.put("2,9",5);
connections.put("3,8",5);
connections.put("3,10",6);
connections.put("4,6",5);
connections.put("4,11",7);
connections.put("4,13",8);
connections.put("5,12",8);
connections.put("5,14",9);
connections.put("6,13",9);
connections.put("6,15",10);
connections.put("7,9",8);
connections.put("8,10",9);
connections.put("11,13",12);
connections.put("12,14",13);
connections.put("13,15",14);
}
static public int getHoppedNode(int x, int y ) {
int lowest = Math.min(x,y);
int highest = Math.max(x,y);
Integer value = connections.get(lowest+","+highest);
if ( value == null )
return -1;
else
return value;

}

}


(This article is a placeholder, I'm going to come back and comment later)

Thursday, June 18, 2009

Too many open files

I owned a web server about a year ago that would crash every other night. I did everything I could to try to track down the exception (Too many open files), but I couldn't figure out what was causing it. I eventually chalked it up to a glassfish bug since they did have that problem before.

Well today I hit it again, this time in a tomcat instance. I ran across a form posting suggesting I try this command:

ls -l /proc/[pid]/fd

Which is an awesome command that I wish I knew about a year ago. This showed all the files that were opened which were indeed my fault. The problem came from a dom4j reader that wasn't being closed which was leaking the file connection. By closing the datastream the problem went away.

So if you have this problem on linux try the above command and see who is opening that file.


Hope that helps,
Chris

Wednesday, April 22, 2009

Use Python to post to twitter

Here is an example of using python to post to twitter.

def twit(login, password, msg):

payload= {'status' : msg, 'source' : 'TinyBlurb'}
payload= urllib.urlencode(payload)

base64string = base64.encodestring('%s:%s' % (login, password))[:-1]
headers = {'Authorization': "Basic %s" % base64string}
url = "http://twitter.com/statuses/update.xml"

result = urlfetch.fetch(url, payload=payload, method=urlfetch.POST, headers=headers)

return result.content

Tuesday, April 21, 2009

Find all files that aren't in perforce

dir /s/b/a-d | p4 -x- have > nul: 2>missing.txt

Friday, April 10, 2009

Returning immutable collections

Many times it is desirable to return an internal collection object to consumers of your class.

For example:

class Foo {
List _internalObjects = new ArrayList();

List getList() {
return _internalObjects;
}
}


The method above works, but has a draw back. The elements of your internalObjects list are now mutable outside your control. In C++ you might try to return const& instead to get around this problem, but how do you solve this in Java?

The first approach might be to return a copy. e.g:
class Foo {
List _internalObjects = new ArrayList();

List getList() {
List copy = new ArrayList();
copy.addAll(_internalObjects);
return copy;
}
}


This has the desired effect but with a couple of disadvantages. First you had to perform the copy which could be a performance bottleneck. Second the consumer may no longer point to the same objects if you modify your internalObject class.

The best way, that I know of, to do this is as follows:

class Foo {
final List _internalObjects = new ArrayList();

List getList() {

return new AbstractList() {
@Override
public Object get(int index)
{
return _internalObjects.get(index);
}
@Override
public int size()
{
return _internalObjects.size();
}
};
}
}


The returned list still points to internal list, but is read only. Also, just to be pedantic, I've marked the list as final which means the reference will never change which is more correct for this example.

I hope that helps, leave comments on what you think.

@developresource

Friday, March 27, 2009

Add new line at end of file.

Working on a cross platform c++ project I find it annoying that Linux requires a new line at the end of each file. I constantly forget to do this.

I wrote this simple macro which will add the new line each time you save a file.

You don't need the whole thing. Most of this is generated in EnvironmentEvents but saved here for posterity.



Option Strict Off
Option Explicit Off
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module EnvironmentEvents

#Region "Automatically generated code, do not modify"
'Automatically generated code, do not modify
'Event Sources Begin
Public WithEvents DTEEvents As EnvDTE.DTEEvents
Public WithEvents DocumentEvents As EnvDTE.DocumentEvents
Public WithEvents WindowEvents As EnvDTE.WindowEvents
Public WithEvents TaskListEvents As EnvDTE.TaskListEvents
Public WithEvents FindEvents As EnvDTE.FindEvents
Public WithEvents OutputWindowEvents As EnvDTE.OutputWindowEvents
Public WithEvents SelectionEvents As EnvDTE.SelectionEvents
Public WithEvents BuildEvents As EnvDTE.BuildEvents
Public WithEvents SolutionEvents As EnvDTE.SolutionEvents
Public WithEvents SolutionItemsEvents As EnvDTE.ProjectItemsEvents
Public WithEvents MiscFilesEvents As EnvDTE.ProjectItemsEvents
Public WithEvents DebuggerEvents As EnvDTE.DebuggerEvents
Public WithEvents ProjectsEvents As EnvDTE.ProjectsEvents
Public WithEvents TextDocumentKeyPressEvents As EnvDTE80.TextDocumentKeyPressEvents
Public WithEvents CodeModelEvents As EnvDTE80.CodeModelEvents
Public WithEvents DebuggerProcessEvents As EnvDTE80.DebuggerProcessEvents
Public WithEvents DebuggerExpressionEvaluationEvents As EnvDTE80.DebuggerExpressionEvaluationEvents
'Event Sources End
'End of automatically generated code
#End Region




Private Sub DocumentEvents_DocumentOpened(ByVal Document As EnvDTE.Document) Handles DocumentEvents.DocumentOpened

End Sub

Private Sub DocumentEvents_DocumentSaved(ByVal Document As EnvDTE.Document) Handles DocumentEvents.DocumentSaved

Dim textSelection As EnvDTE.TextSelection

textSelection = CType(DTE.ActiveDocument.Selection(), EnvDTE.TextSelection)
textSelection.EndOfDocument(True)
textSelection.EndOfLine()
If textSelection.Text <> vbCrLf Then
textSelection.Text = textSelection.Text & vbCrLf
End If



End Sub
End Module

Visual Studio Macros for source control.

Visual Studio allows for users to customize the environment by writing macros. With Visual Studio 2008 the macros can be written in VB.Net. VB.Net is a very powerful language as it can use any of the standard .NET object, and in addition it has access to Visual Studios ENVDTE object.

The following set of macros replace the buggy Perforce source control plugin.


Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module MiscCommands
Sub P4Add()
Dim filename As String = DTE.ActiveWindow.Document.FullName
ChDir("c:\p4")
ExecuteCommand("p4.exe", "add " + filename)
End Sub

Sub P4Edit()
Dim filename As String = DTE.ActiveWindow.Document.FullName
ChDir("c:\p4")
ExecuteCommand("p4.exe", "edit " + filename)
End Sub

Sub P4Diff()
Dim filename As String = DTE.ActiveWindow.Document.FullName
ChDir("c:\p4")
ExecuteCommand("p4.exe", "diff " + filename)
End Sub

Sub P4Revert()
Dim filename As String = DTE.ActiveWindow.Document.FullName
ChDir("c:\p4")
ExecuteCommand("p4.exe", "revert " + filename)
End Sub

Sub P4Opened()
ChDir("c:\p4")
ExecuteCommand("p4.exe", "opened")
End Sub

Sub P4History()
Dim filename As String = DTE.ActiveWindow.Document.FullName
ChDir("c:\p4")
ExecuteCommand("p4.exe", "filelog " + filename)
End Sub

Public Sub ExecuteCommand(ByVal filename As String, ByVal arguments As String)

Dim p As New System.Diagnostics.Process
p.StartInfo.UseShellExecute = False
p.StartInfo.FileName = filename
p.StartInfo.Arguments = arguments
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.RedirectStandardError = True
p.Start()
p.WaitForExit()


WriteToMyNewPane(filename + " " + arguments, p.StandardOutput.ReadToEnd + p.StandardError.ReadToEnd)


End Sub

Public Sub WriteToMyNewPane(ByVal command As String, ByVal results As String)
Dim win As Window = _
DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
Dim ow As OutputWindow = win.Object
Dim owPane As OutputWindowPane
Dim cnt As Integer = ow.OutputWindowPanes.Count
owPane = ow.OutputWindowPanes.Item(1)
owPane.OutputString(command & vbCrLf)
owPane.OutputString(results & vbCrLf)
owPane.Activate()
End Sub


Sub OpenFile()
Dim fileName As String = InputBox("Open file:")
If String.IsNullOrEmpty(fileName) Then
Return
End If
Dim item As EnvDTE.ProjectItem = DTE.Solution.FindProjectItem(fileName)
If item Is Nothing Then
MsgBox("File not found", MsgBoxStyle.Exclamation)
Return
End If
item.Open()
item.Document.Activate()
End Sub

End Module