Skip to content

Instantly share code, notes, and snippets.

@tamamu
Created May 1, 2020 13:50
Show Gist options
  • Save tamamu/8e2803ede64dedc0ba608ccb09f0a1df to your computer and use it in GitHub Desktop.
Save tamamu/8e2803ede64dedc0ba608ccb09f0a1df to your computer and use it in GitHub Desktop.
N-moku written in JavaScript (p5.js)
const Player = {
NONE: 0,
RED: 1,
BLUE: 2,
}
let global = {
size: {x: 5, y: 5},
left: 640/2 - 300/2,
top: 10,
width: 300,
height: 300,
logs: [],
game: null,
turn: Player.RED,
requireCount: 3,
isGameOver: false,
autoplay: true,
delta: 0,
};
console.log = msg => global.logs.push(msg);
function setup() {
const {size} = global;
reset();
updateStage();
}
function reset() {
const {size} = global;
global.logs = []
global.turn = 1;
global.isGameOver = false;
global.game = new Array(size.y)
.fill()
.map(() => (
new Array(size.x)
.fill()
.map(() => Player.NONE)))
notice();
}
function updateStage() {
const {size, left, top, width, height, game} = global;
createCanvas(640, 480);
fill("red");
rect(0, 0, 320, 480);
fill("blue")
rect(320, 0, 320, 480)
fill("white");
stroke("black");
rect(left, top, width, height);
for (let i=1; i < size.y; i++) {
const y = height/size.y*i;
line(left, top+y, left+width, top+y);
}
for (let i=1; i < size.x; i++) {
const x = width/size.x*i;
line(left+x, top, left+x, top+height);
}
for (let x=0; x < size.x; x++) {
for (let y=0; y < size.y; y++) {
switch (game[y][x]) {
case Player.NONE:
fill(0, 0, 0, 0);
break;
case Player.RED:
fill("red");
break;
case Player.BLUE:
fill("blue");
break;
}
stroke(0, 0, 0, 0);
ellipse(
left + x * width / size.x + width / (size.x*2),
top + y * height / size.y + height / (size.y*2),
width / size.x * 0.75,
height / size.y * 0.75,
);
}
}
}
function checkGameOver() {
const {size, game, turn, requireCount} = global;
let win = false;
for (let y=0; y < size.y; y++) {
for (let x=0; x < size.x; x++) {
if (game[y][x] !== turn) continue;
// right
let rightAccum = 0;
for (let i=0; x+i < size.x; i++) {
if (game[y][x+i] === turn) {
rightAccum += 1;
} else {
break;
}
}
if (rightAccum >= requireCount) {
win = true;
break;
}
// down-right
drAccum = 0;
if (size.x - x < size.y - y) { // down-axis is long
for (let i=0;
x + i < size.x;
i++)
{
if (game[y+i][x+i] === turn) {
drAccum += 1;
} else {
break;
}
}
} else {
for (let i=0;
y + i < size.y;
i++)
{
if (game[y+i][x+i] === turn) {
drAccum += 1;
} else {
break;
}
}
}
if (drAccum >= requireCount) {
win = true;
break;
}
// down-left
dlAccum = 0;
if (x < size.y - y) { // down-axis is long
for (let i=0;
x - i >= 0;
i++)
{
if (game[y+i][x-i] === turn) {
dlAccum += 1;
} else {
break;
}
}
} else {
for (let i=0;
y + i < size.y;
i++)
{
if (game[y+i][x-i] === turn) {
dlAccum += 1;
} else {
break;
}
}
}
if (dlAccum >= requireCount) {
win = true;
break;
}
// down
let downAccum = 0;
for (let i=0; y+i < game.length; i++) {
if (game[y+i][x] === turn) {
downAccum += 1;
} else {
break;
}
}
if (downAccum >= requireCount) {
win = true;
break;
}
}
if (win) {
break;
}
}
if (win) {
console.log(`${turn === Player.RED ? "赤" : "青"}の勝ち!なんで負けたか明日まで考えといてください。`);
console.log(`クリックでNEW GAME!!`);
global.isGameOver = true;
return true;
}
// check draw
let fillCount = false;
for (let y=0; y < size.y; y++) {
for (let x=0; x < size.x; x++) {
if (game[y][x] !== Player.NONE) {
fillCount += 1;
}
}
}
if (fillCount === size.x * size.y) {
console.log("引き分け!");
console.log("クリックでNEW GAME!!");
global.isGameOver = true;
return true;
}
}
function draw() {
global.delta += deltaTime;
const {left, top, width, height, logs, autoplay, isGameOver} = global;
fill("white");
stroke("black");
rect(0, top+height, 640, 480-(top+height));
fill("black");
stroke(0, 0, 0, 0);
textSize(16);
for (let i=0; i < Math.min(logs.length, 10); i++) {
text(logs[i+Math.max(logs.length-10, 0)], 0, top+height+i*16+16);
}
if (global.delta > 10 && autoplay) {
if (isGameOver) {
reset();
updateStage();
} else {
auto();
global.delta = 0;
}
}
}
function auto() {
const {size, game} = global;
let nones = []
for (let y=0; y < size.y; y++) {
for (let x=0; x < size.x; x++) {
if (game[y][x] === Player.NONE) {
nones.push([x, y]);
}
}
}
if (nones.length > 0) {
const next = nones[Math.floor(Math.random() * nones.length)];
put(next[0], next[1])
}
}
function mouseClicked(ev) {
const {size, left, top, width, height, isGameOver} = global;
if (isGameOver) {
reset();
updateStage();
return;
}
const x = Math.floor((ev.clientX - left) / (width / size.x));
const y = Math.floor((ev.clientY - top) / (height / size.y));
put(x, y);
}
function put(x, y) {
const {size, game, turn} = global;
if (x < 0 || y < 0 || size.x <= x || size.y <= y) return;
if (game[y][x] !== 0) return;
game[y][x] = turn;
updateStage();
if (checkGameOver()) return;
global.turn += 1;
if (global.turn > 2) global.turn = Player.RED;
notice();
}
function notice() {
console.log(`${global.turn === Player.RED ? "赤" : "青"}の番やで`);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment