Compare commits

26 Commits

Author SHA1 Message Date
893ffe4aa4 make it possible for ai to make the first move 2022-07-29 05:53:52 +00:00
f71602f385 learn from multiple games with fresh model each 2022-07-29 05:35:58 +00:00
OezmenK
539b3c02f5 finished Tic-Tac-Toe Project 2022-07-26 15:29:57 +02:00
3ab800f967 renable modern tfjs 2022-07-19 19:24:38 +00:00
69223a513f fix allmoves to contain all flipped moves 2022-07-19 19:21:36 +00:00
80e67f41d7 fix flipY method 2022-07-19 19:21:20 +00:00
c2aa53ac88 enable ai training 2022-07-19 19:02:27 +00:00
21ffed5566 revert to tfjs 1.7.4 and fix compile-bug 2022-07-19 19:02:09 +00:00
1197fcbcad add more eslint ignores, for now. fix this! 2022-07-19 19:01:44 +00:00
OezmenK
9e542c64ba added train buttons 2022-07-19 14:54:29 +02:00
OezmenK
907284b098 Merge branch 'development' of https://gitea.tahir-it.de/david.tahir/AngularTicTacToe into development 2022-07-19 14:52:57 +02:00
OezmenK
877f6cd529 added bug fix for tf 2022-07-19 14:48:38 +02:00
unknown
13fe8d511e added @types/long to packages and edited compilerOptions 2022-07-19 14:44:37 +02:00
6eb2d78f8c disable es-lint for now 2022-07-19 12:33:22 +00:00
OezmenK
6e97d11f43 added history 2022-07-19 13:40:44 +02:00
OezmenK
0226cb9cfb fresh package pull 2022-07-12 14:02:42 +02:00
OezmenK
ae1cd8944c Merge branch 'development' of https://gitea.tahir-it.de/david.tahir/AngularTicTacToe into development 2022-07-12 13:40:47 +02:00
OezmenK
88e25143bf added ai.service.ts file 2022-06-29 07:48:24 +02:00
OezmenK
a34dec4f43 added tensorflow/tfjs 2022-06-29 07:48:00 +02:00
David Tahir
f51f89e3b0 added devcontainers 2022-06-28 12:27:49 +00:00
OezmenK
2a47eb6b20 deleted translate 2022-06-28 13:46:32 +02:00
OezmenK
85267bfe2c changed winning conditions 2022-06-28 13:45:54 +02:00
OezmenK
62bf421c9b adde top down vertical test 2022-06-28 13:45:14 +02:00
OezmenK
fd9be97387 changed browser window size 2022-06-28 13:44:43 +02:00
OezmenK
bc829346ae added nebular theme 2022-06-28 13:43:54 +02:00
Oezmen
2e0c68a636 changes 2022-06-14 14:27:32 +02:00
20 changed files with 3432 additions and 1907 deletions

14
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
# [Optional] Uncomment if you want to install more global node modules
# RUN su node -c "npm install -g <your-package-list-here>"

View File

@@ -0,0 +1,55 @@
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM node:${VARIANT}
# [Option] Install zsh
ARG INSTALL_ZSH="true"
# [Option] Upgrade OS packages to their latest versions
ARG UPGRADE_PACKAGES="true"
# Install needed packages, yarn, nvm and setup non-root user. Use a separate RUN statement to add your own dependencies.
ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
ARG NPM_GLOBAL=/usr/local/share/npm-global
ENV NVM_DIR=/usr/local/share/nvm
ENV NVM_SYMLINK_CURRENT=true \
PATH=${NPM_GLOBAL}/bin:${NVM_DIR}/current/bin:${PATH}
COPY library-scripts/*.sh library-scripts/*.env /tmp/library-scripts/
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# Remove imagemagick due to https://security-tracker.debian.org/tracker/CVE-2019-10131
&& apt-get purge -y imagemagick imagemagick-6-common \
# Install common packages, non-root user, update yarn and install nvm
&& bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \
# Install yarn, nvm
&& rm -rf /opt/yarn-* /usr/local/bin/yarn /usr/local/bin/yarnpkg \
&& bash /tmp/library-scripts/node-debian.sh "${NVM_DIR}" "none" "${USERNAME}" \
# Configure global npm install location, use group to adapt to UID/GID changes
&& if ! cat /etc/group | grep -e "^npm:" > /dev/null 2>&1; then groupadd -r npm; fi \
&& usermod -a -G npm ${USERNAME} \
&& umask 0002 \
&& mkdir -p ${NPM_GLOBAL} \
&& touch /usr/local/etc/npmrc \
&& chown ${USERNAME}:npm ${NPM_GLOBAL} /usr/local/etc/npmrc \
&& chmod g+s ${NPM_GLOBAL} \
&& npm config -g set prefix ${NPM_GLOBAL} \
&& sudo -u ${USERNAME} npm config -g set prefix ${NPM_GLOBAL} \
# Install eslint
&& su ${USERNAME} -c "umask 0002 && npm install -g eslint" \
&& npm cache clean --force > /dev/null 2>&1 \
# Install python-is-python3 on bullseye to prevent node-gyp regressions
&& . /etc/os-release \
&& if [ "${VERSION_CODENAME}" = "bullseye" ]; then apt-get -y install --no-install-recommends python-is-python3; fi \
# Clean up
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /root/.gnupg /tmp/library-scripts
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
# [Optional] Uncomment if you want to install more global node modules
# RUN su node -c "npm install -g <your-package-list-here>""

View File

@@ -0,0 +1,32 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/javascript-node
{
"name": "Node.js",
"build": {
"dockerfile": "Dockerfile",
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
// Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local arm64/Apple Silicon.
"args": { "VARIANT": "16-bullseye" }
},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node"
}

View File

@@ -16,8 +16,8 @@ function createWindow(): BrowserWindow {
win = new BrowserWindow({
x: 0,
y: 0,
width: size.width,
height: size.height,
width: 650,
height: 700,
webPreferences: {
nodeIntegration: true,
allowRunningInsecureContent: (serve) ? true : false,

4897
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -45,14 +45,20 @@
"lint": "ng lint"
},
"dependencies": {
"@angular/common": "13.3.1",
"@angular/compiler": "13.3.1",
"@angular/core": "13.3.1",
"@angular/forms": "13.3.1",
"@angular/language-service": "13.3.1",
"@angular/platform-browser": "13.3.1",
"@angular/platform-browser-dynamic": "13.3.1",
"@angular/router": "13.3.1",
"@angular/animations": "13.3.11",
"@angular/cdk": "^13.0.0",
"@angular/common": "13.3.11",
"@angular/compiler": "13.3.11",
"@angular/core": "13.3.11",
"@angular/forms": "13.3.11",
"@angular/language-service": "13.3.11",
"@angular/platform-browser": "13.3.11",
"@angular/platform-browser-dynamic": "13.3.11",
"@angular/router": "13.3.11",
"@nebular/eva-icons": "9.0.3",
"@nebular/theme": "9.0.3",
"@tensorflow/tfjs": "1.7.4",
"eva-icons": "^1.1.2",
"rxjs": "7.5.5",
"tslib": "^2.1.0",
"zone.js": "~0.11.5"
@@ -66,12 +72,14 @@
"@angular-eslint/schematics": "13.1.0",
"@angular-eslint/template-parser": "13.1.0",
"@angular/cli": "13.3.1",
"@angular/compiler-cli": "13.3.1",
"@angular/compiler-cli": "13.3.11",
"@ngx-translate/core": "14.0.0",
"@ngx-translate/http-loader": "7.0.0",
"@playwright/test": "1.20.2",
"@schematics/angular": "13.3.1",
"@types/jasmine": "3.10.3",
"@types/jasminewd2": "2.0.10",
"@types/long": "4.0.2",
"@types/node": "17.0.23",
"@typescript-eslint/eslint-plugin": "5.17.0",
"@typescript-eslint/parser": "5.17.0",

164
src/app/ai.service.ts Normal file
View File

@@ -0,0 +1,164 @@
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable @typescript-eslint/no-unused-expressions */
/* eslint-disable space-before-function-paren */
/* eslint-disable prefer-const */
/* eslint-disable @typescript-eslint/quotes */
/* eslint-disable @typescript-eslint/member-ordering */
import * as tf from "@tensorflow/tfjs";
export class AiService {
constructor() {
}
async doPredict(myBoard) {
const tenseBlock = tf.tensor([myBoard]);
const result = await this.currentModel.predict(tenseBlock);
const flatty = result.flatten();
const maxy = flatty.argMax();
const move = await maxy.data();
const allMoves = await flatty.data();
flatty.dispose();
tenseBlock.dispose();
result.dispose();
maxy.dispose();
return [move[0], allMoves];
};
private currentModel;
flipX(arr) {
return [arr.slice(6), arr.slice(3, 6), arr.slice(0, 3)].flat();
};
flipY(arr) {
return this.flipX(arr.slice().reverse());
}
// Creates a 1 hot of the diff
showMove(first, second) {
let result = [];
first.forEach((move, i) => {
result.push(Math.abs(move - second[i]));
});
return result;
};
getMoves (block) {
let x = [];
let y = [];
// Make all the moves
for (let i = 0; i < block.length - 1; i++) {
const theMove = this.showMove(block[i], block[i + 1]);
// Normal move
x.push(block[i]);
y.push(theMove);
// Flipped X move
x.push(this.flipX(block[i]));
y.push(this.flipX(theMove));
// Inverted Move
x.push(block[i].slice().reverse());
y.push(theMove.slice().reverse());
// Flipped Y move
x.push(this.flipY(block[i]));
y.push(this.flipY(theMove));
}
return { x, y };
};
constructModel() {
this.currentModel && this.currentModel.dispose();
tf.disposeVariables();
const model = tf.sequential();
model.add(
tf.layers.dense({
inputShape: [9],
units: 64,
activation: "relu"
})
);
model.add(
tf.layers.dense({
units: 64,
activation: "relu"
})
);
model.add(
tf.layers.dense({
units: 9,
activation: "softmax"
})
);
const learningRate = 0.005;
model.compile({
optimizer: tf.train.adam(learningRate),
loss: "categoricalCrossentropy",
metrics: ["accuracy"]
});
this.currentModel = model;
return model;
};
getModel() {
if (this.currentModel) {
return this.currentModel;
} else {
return this.constructModel();
}
};
async trainOnGames(games, setState) {
const model = this.constructModel();
// model.dispose();
let AllX = [];
let AllY = [];
// console.log("Games in", JSON.stringify(games));
games.forEach((game) => {
AllX = AllX.concat(game.x);
AllY = AllY.concat(game.y);
});
// Tensorfy!
console.log(AllX);
const stackedX = tf.stack(AllX);
const stackedY = tf.stack(AllY);
await this.trainModel(model, stackedX, stackedY);
// clean up!
stackedX.dispose();
stackedY.dispose();
setState(model);
// return updatedModel;
};
async trainModel (model, stackedX, stackedY) {
const allCallbacks = {
// onTrainBegin: log => console.log(log),
// onTrainEnd: log => console.log(log),
// onEpochBegin: (epoch, log) => console.log(epoch, log),
onEpochEnd: (epoch, log) => console.log(epoch, log)
// onBatchBegin: (batch, log) => console.log(batch, log),
// onBatchEnd: (batch, log) => console.log(batch, log)
};
await model.fit(stackedX, stackedY, {
epochs: 100,
shuffle: true,
batchSize: 32,
callbacks: allCallbacks
});
console.log("Model Trained");
return model;
};
}

View File

@@ -1 +1,15 @@
<app-board></app-board>
<nb-layout>
<nb-layout-header fixed>
<!-- Insert header here -->
</nb-layout-header>
<nb-layout-column>
<app-board></app-board>
</nb-layout-column>
<nb-layout-footer fixed>
<!-- Insert footer here -->
</nb-layout-footer>
</nb-layout>