Source code
<script id="snake.pl" type="text/prolog">
:- use_module(library(lists)).
:- use_module(library(random)).
:- use_module(library(dom)).
:- use_module(library(js)).
:- use_module(library(os)).
:- dynamic(direction/1).
direction(down).
key_direction(w, up) :-
direction(Direction),
Direction \== down.
key_direction(a, left) :-
direction(Direction),
Direction \== right.
key_direction(d, right) :-
direction(Direction),
Direction \== left.
key_direction(s, down) :-
direction(Direction),
Direction \== up.
snake :-
once(get_by_tag(body, Body)),
bind(Body, keydown, Event, (
event_property(Event, key, Key),
key_direction(Key, Direction),
prevent_default(Event),
retractall(direction(_)),
asserta(direction(Direction))
)),
get_by_id(snake, Canvas),
apply(Canvas, getContext, ['2d'], Ctx),
random_between(1, 20, X),
random_between(1, 20, Y),
snake(Ctx, [(1,1)], (X,Y)).
snake(Ctx, Snake, Point) :-
get_time(T0),
draw(Ctx, Snake, Point),
direction(Direction),
update(Snake, Point, Direction, Snake1, Point1),
get_time(T1),
Timeout is max(0, 60-round(T1-T0)),
set_timeout(Timeout, snake(Ctx, Snake1, Point1), _).
next_position(left, (1,Y), (20,Y)).
next_position(left, (X0,Y), (X1,Y)) :-
succ(X1, X0).
next_position(right, (20,Y), (1,Y)).
next_position(right, (X0,Y), (X1,Y)) :-
succ(X0, X1).
next_position(up, (X,1), (X,20)).
next_position(up, (X,Y0), (X,Y1)) :-
succ(Y1, Y0).
next_position(down, (X,20), (X,1)).
next_position(down, (X,Y0), (X,Y1)) :-
succ(Y0, Y1).
inits([_], []).
inits([X,Y|T], [X|S]) :-
inits([Y|T], S).
update(Snake0, Point0, Direction, [Head1|Snake1], Point1) :-
Snake0 = [Head0|_],
next_position(Direction, Head0, Head1),
( member(Head1, Snake0) ->
Snake1 = [],
Point1 = Point0 ;
( Head1 == Point0 ->
Snake1 = Snake0,
Point1 = (X,Y),
random_between(1,20,X),
random_between(1,20,Y)
; inits(Snake0, Snake1),
Point1 = Point0
)
).
draw(Ctx, Snake, Point) :-
apply(Ctx, clearRect, [0,0,200,200], _),
draw_point(Ctx, Point, red),
forall(
member(Body, Snake),
draw_point(Ctx, Body, black)
).
draw_point(Ctx, (X,Y), Color) :-
PointX is (X-1)*10,
PointY is (Y-1)*10,
set_prop(Ctx, fillStyle, Color),
apply(Ctx, beginPath, [], _),
apply(Ctx, rect, [PointX,PointY,10,10], _),
apply(Ctx, fill, [], _).
</script>
<style type="text/css">
#snake {
border: 2px solid black;
}
</style>
<canvas id="snake" width="200" height="200"></canvas>
<div><kbd>W</kbd> <kbd>A</kbd> <kbd>S</kbd> <kbd>D</kbd> to play</div>
<script type="text/javascript">
var session = pl.create();
session.consult("snake.pl", function() {
session.query("snake.", function() {
session.answer();
});
});
</script>