Last active
December 13, 2015 23:29
-
-
Save adrianseeley/4992008 to your computer and use it in GitHub Desktop.
Light Cycles in NodeJS! Plus Naive Neural Network (:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var GAME_WIDTH = 10; | |
var GAME_HEIGHT = 10; | |
var EMPTY = ' '; | |
var FULL = 'O'; | |
function cls() { process.stdout.write('\u001B[2J\u001B[0;0f'); } | |
function replace (string, index, character) { return string.substr(0, index) + character + string.substr(index + character.length); } | |
function get_new_game(players) | |
{ | |
var board = ''; for(var h = 0; h < GAME_HEIGHT; h++) for(var w = 0; w < GAME_WIDTH; w++) if(w == 0 || w == GAME_WIDTH - 1 || h == 0 || h == GAME_HEIGHT - 1) board += FULL; else board += EMPTY; | |
if(players >= 1) board = board.substr(0, GAME_WIDTH + 1) + '1' + board.substr(GAME_WIDTH + 1 + 1); | |
if(players >= 2) board = board.substr(0, board.length - GAME_WIDTH - 2) + '2' + board.substr(board.length - GAME_WIDTH - 2 + 1); | |
return { board: board, frame: 0 }; | |
} | |
function draw_game(game) { cls(); for(var h = 0; h < GAME_HEIGHT; h++) console.log(game.board.substr(h * GAME_WIDTH, GAME_WIDTH)); } | |
function do_frame(game, done_callback) | |
{ | |
var player_locations = []; | |
var player_at_location = []; | |
var player_moves = []; | |
// grab players, replace their positions with FULLs | |
for(var p = 0; p < game.board.length; p++) if(game.board[p] != EMPTY && game.board[p] != FULL) { player_locations.push(p); player_at_location.push(game.board[p]); game.board = replace(game.board, p, FULL); } | |
// if we have at least 2 players, process moves | |
if(player_locations.length > 1) | |
{ | |
for(var p = 0; p < player_locations.length; p++) | |
{ | |
var board_for_player = game.board; | |
for(var b = 0; b < player_locations.length; b++) | |
{ | |
if(p == b) board_for_player = replace(board_for_player, player_locations[b], '+'); | |
else board_for_player = replace(board_for_player, player_locations[b], '-'); | |
} | |
player_moves.push(get_move(board_for_player, player_at_location[p])); | |
} | |
for(var m = 0; m < player_moves.length; m++) | |
{ | |
switch(player_moves[m]) | |
{ | |
case 'n': if(game.board[player_locations[m] - GAME_WIDTH] == EMPTY) game.board = replace(game.board, player_locations[m] - GAME_WIDTH, player_at_location[m]); else if(game.board[player_locations[m] - GAME_WIDTH] != EMPTY && game.board[player_locations[m] - GAME_WIDTH] != FULL) replace(game.board, player_locations[m] - GAME_WIDTH, FULL); break; | |
case 's': if(game.board[player_locations[m] + GAME_WIDTH] == EMPTY) game.board = replace(game.board, player_locations[m] + GAME_WIDTH, player_at_location[m]); else if(game.board[player_locations[m] + GAME_WIDTH] != EMPTY && game.board[player_locations[m] + GAME_WIDTH] != FULL) replace(game.board, player_locations[m] + GAME_WIDTH, FULL); break; | |
case 'e': if(game.board[player_locations[m] + 1] == EMPTY) game.board = replace(game.board, player_locations[m] + 1, player_at_location[m]); else if(game.board[player_locations[m] + 1] != EMPTY && game.board[player_locations[m] + 1] != FULL) replace(game.board, player_locations[m] + 1, FULL); break; | |
case 'w': if(game.board[player_locations[m] - 1] == EMPTY) game.board = replace(game.board, player_locations[m] - 1, player_at_location[m]); else if(game.board[player_locations[m] - 1] != EMPTY && game.board[player_locations[m] - 1] != FULL) replace(game.board, player_locations[m] - 1, FULL); break; | |
} | |
} | |
game.frame++; | |
draw_game(game); | |
setTimeout(function () { done_callback(game, do_frame); }, 1000); | |
} | |
// if we have only 1 player, they are the winner | |
else if(player_locations.length == 1) | |
{ | |
console.log('winner: ' + player_at_location[0]); | |
aether_end_game(parseInt(player_at_location[0]) - 1); | |
do_frame(get_new_game(2), do_frame); | |
} | |
// otherwise the last two players died on the same frame, its a draw | |
else | |
{ | |
console.log('draw :/'); | |
aether_end_game(-1); | |
do_frame(get_new_game(2), do_frame); | |
} | |
} | |
function get_move(board, player) | |
{ | |
if(player == '1') return aether_get_move(board, 1 - 1); | |
if(player == '2') return aether_get_move(board, 2 - 1); | |
} | |
var aether = {}; | |
var trail = [[], []]; | |
function aether_get_move(board, player) | |
{ | |
var awareness = aether_build_awareness(board); | |
if(aether[awareness]) | |
{ | |
var highest = 'n'; | |
var at = aether[awareness].n; | |
if(aether[awareness].s > at) { highest = 's'; at = aether[awareness].s; } | |
if(aether[awareness].e > at) { highest = 'e'; at = aether[awareness].e; } | |
if(aether[awareness].w > at) { highest = 'w'; at = aether[awareness].w; } | |
trail[player].push({awareness: awareness, move: highest}); | |
return highest; | |
} | |
else | |
{ | |
var options = ['n', 's', 'e', 'w']; | |
var random = options[Math.floor(Math.random() * options.length)]; | |
trail[player].push({awareness: awareness, move: random}); | |
return random; | |
} | |
} | |
function aether_build_awareness(board) | |
{ | |
var awareness = ''; | |
var rows = []; | |
var my_x, my_r; | |
for(var r = 0; r < GAME_HEIGHT; r++) rows.push(board.substr(r * GAME_WIDTH, GAME_WIDTH)); | |
out_of_nested_for: for(var r = 0; r < rows.length; r++) for(var x = 0; x < rows[r].length; x++) if(rows[r][x] == '+') { my_x = x; my_r = r; break out_of_nested_for; } | |
//build 5 x 5 awareness | |
for(var r = my_r - 3; r < my_r + 2; r++) | |
{ | |
for(var x = my_x - 3; x < my_x + 2; x++) | |
{ | |
if(r < 0 || r >= GAME_HEIGHT || x < 0 || x >= GAME_WIDTH || (x == my_x && r == my_r)) awareness += FULL; | |
else awareness += rows[r][x]; | |
} | |
} | |
console.log(awareness); | |
return awareness; | |
} | |
function aether_end_game(winner) | |
{ | |
for(var p = 0; p < trail.length; p++) | |
{ | |
for(var t = 0; t < trail[p].length; t++) | |
{ | |
if(!aether[trail[p][t].awareness]) aether[trail[p][t].awareness] = {n: -1, s: -1, e: -1, w: -1}; | |
if(p == winner) aether[trail[p][t].awareness] [trail[p][t].move]++; | |
else aether[trail[p][t].awareness] [trail[p][t].move]--; | |
} | |
} | |
delete trail; trail = [[], []]; | |
return; | |
} | |
do_frame(get_new_game(2), do_frame); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment