Late November I made this Wooden Dowel Christmas Tree with advent-style felt ornaments (with some talented friends helping with all the ornaments).
The tree is collapsible (you just pull the branches out) which is useful for the rest of the year when its not Christmas!
Even Steven is now available as a free download on the App Store
Feedback welcomed via Twitter
Thanks to people that helped test it!
Update Now available on the App Store!
Even Steven is a handy app that records group spending for events such as holidays and suggests who needs to pay what to whom in order to get even!
Even Steven is designed for iPhone and:
Behind the scenes, Even Steven is a pure Swift3 iOS app and uses no third party libraries.
... ➦Still horrendous at making things with my hands but will keep trying! This is a tealight holder that is basically three bits of wood, two drill holes and glue.
Tensorflow seems like a pretty exciting alternative to scikit-learn
that works just as effectively for beginners as it does for pros.
For my team’s monthly drink’n’sync I wrote an interactive worksheet on using TensorFlow to build a handwritten number detector.
Check it out on github!
This is a crude example of a playable game that can be expressed in less than 250 lines of code!
1<!DOCTYPE html>
2<html>
3<body>
4 <canvas id="game"> </canvas>
5 <script type="text/javascript">
6 var game = (function() {
7 var Width = 800, Height = 450;
8 var canvas = document.getElementById("game");
9 var FPS = 1000 / 60;
10 canvas.width = Width;
11 canvas.height = Height;
12 canvas.setAttribute('tabindex', 1);
13 var ctx = canvas.getContext("2d");
14
15 var BG = {
16 Color: '#333',
17 Paint: function() {
18 ctx.fillStyle = this.Color;
19 ctx.fillRect(0, 0, Width, Height);
20 }
21 };
22
23 var Ball = { Radius: 5, Color: '#999', X: 0, Y: 0, VelX: 0, VelY: 0 };
24 Ball.Paint = function() {
25 ctx.beginPath();
26 ctx.fillStyle = this.Color;
27 ctx.arc(this.X, this.Y, this.Radius, 0, Math.PI * 2, false);
28 ctx.fill();
29 this.Update();
30 };
31 Ball.Update = function() {
32 this.X += this.VelX;
33 this.Y += this.VelY;
34 };
35 Ball.Reset = function() {
36 this.X = Width / 2;
37 this.Y = Height / 2;
38 this.VelX = (!!Math.round(Math.random() * 1) ? 1.5 : -1.5);
39 this.VelY = (!!Math.round(Math.random() * 1) ? 1.5 : -1.5);
40 };
41
42 function Paddle(position) {
43 this.Color = '#999';
44 this.Width = 5;
45 this.Height = 100;
46 this.X = 0;
47 this.Y = Height / 2 - this.Height / 2;
48 this.Score = 0;
49 if (position == 'left')
50 this.X = 0;
51 else this.X = Width - this.Width;
52 this.Paint = function() {
53 ctx.fillStyle = this.Color;
54 ctx.fillRect(this.X, this.Y, this.Width, this.Height);
55 ctx.fillStyle = this.Color;
56 ctx.font = "normal 10pt Calibri";
57 if (position == 'left') {
58 ctx.textAlign = "left";
59 ctx.fillText("score: " + Player.Score, 10, 10);
60 } else {
61 ctx.textAlign = "right";
62 ctx.fillText("score: " + Computer.Score, Width - 10, 10);
63 }
64 };
65 this.IsCollision = function() {
66 if (Ball.X - Ball.Radius > this.Width + this.X || this.X > Ball.Radius * 2 + Ball.X - Ball.Radius)
67 return false;
68 if (Ball.Y - Ball.Radius > this.Height + this.Y || this.Y > Ball.Radius * 2 + Ball.Y - Ball.Radius)
69 return false;
70 return true;
71 };
72 };
73
74 window.requestAnimFrame = (function() {
75 return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
76 return window.setTimeout(callback, FPS);
77 };
78 })();
79 window.cancelRequestAnimFrame = (function() {
80 return window.cancelAnimationFrame || window.webkitCancelRequestAnimationFrame || window.mozCancelRequestAnimationFrame || window.oCancelRequestAnimationFrame || window.msCancelRequestAnimationFrame || clearTimeout
81 })();
82
83 var Computer = new Paddle();
84 var Player = new Paddle('left');
85
86 function Paint() {
87 ctx.beginPath();
88 BG.Paint();
89 Computer.Paint();
90 Player.Paint();
91 Ball.Paint();
92 }
93
94 function MouseMove(e) {
95 Player.Y = e.pageY - Player.Height / 2;
96 }
97 canvas.addEventListener("mousemove", MouseMove, true);
98
99 function Loop() {
100 init = requestAnimFrame(Loop);
101 Paint();
102 if (Player.IsCollision() || Computer.IsCollision()) {
103 Ball.VelX = Ball.VelX * -1;
104 Ball.VelX += (Ball.VelX > 0 ? 0.5 : -0.5);
105 if (Math.abs(Ball.VelX) > Ball.Radius * 1.5)
106 Ball.VelX = (Ball.VelX > 0 ? Ball.Radius * 1.5 : Ball.Radius * -1.5);
107 }
108 if (Ball.Y - Ball.Radius < 0 || Ball.Y + Ball.Radius > Height)
109 Ball.VelY = Ball.VelY * -1;
110 if (Ball.X - Ball.Radius <= 0) {
111 Computer.Score++;
112 Ball.Reset();
113 } else if (Ball.X + Ball.Radius > Width) {
114 Player.Score++;
115 Ball.Reset();
116 }
117 if (Computer.Score === 10)
118 GameOver(false);
119 else if (Player.Score === 10)
120 GameOver(true);
121 Computer.Y = (Computer.Y + Computer.Height / 2 < Ball.Y ? Computer.Y + Computer.Vel : Computer.Y - Computer.Vel);
122 };
123
124 function GameOver(win) {
125 cancelRequestAnimFrame(init);
126 BG.Paint();
127 ctx.fillStyle = "#999";
128 ctx.font = "bold 40px Calibri";
129 ctx.textAlign = "center";
130 ctx.fillText((win ? "YOU WON!" : "GAME OVER"), Width / 2, Height / 2);
131 ctx.font = "normal 16px Calibri";
132 ctx.fillText("refresh to replay", Width / 2, Height / 2 + 20);
133 }
134 return {
135 Start: function() {
136 Ball.Reset();
137 Player.Score = 0;
138 Computer.Score = 0;
139 Computer.Vel = 1.25;
140 Loop();
141 }
142 };
143 })();
144 game.Start();
145 </script>
146</body>
147</html>
My team recently switched our applications from Heroku to barebones AWS. The experience made me truely appreciate just how effective Heroku is and how it has made deploying apps as painfree as could be. After all, what good is making an app if nobody can see it!
I’ve also been a huge fan of my Raspberry Pi. Every time I look at it, I feel challenged to think of a cool use for it.
... ➦