Нет проверки на то, что яблоко попадёт на змею.
Чтобы змея не пыталась повернуть на себя и врезаться можно сделать так:
* Добавить новую переменную int newDir
* В функцию restart() добавить dir = newDir = 2;
* В функции tick() изменить код после if (end) {}:
Код
if (keys[KeyEvent.VK_W] && dir != 1) newDir = 0;
if (keys[KeyEvent.VK_S] && dir != 0) newDir = 1;
if (keys[KeyEvent.VK_A] && dir != 3) newDir = 2;
if (keys[KeyEvent.VK_D] && dir != 2) newDir = 3;
if (ticks++ % 30 == 0) {
dir = newDir;