123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- /* game of tic-tac-toe with:
- * custom size of stage
- * custom number of players
- * mixed AI and players
- */
- class WorldTicTacToe extends World {
- /* assets for this world */
- assets() {
- return [
- "images/stage_empty.png",
- "images/stage_p1.png",
- "images/stage_p2.png",
- "images/stage_p3.png",
- "images/stage_p4.png",
- "images/stage_p5.png",
- "images/stage_p6.png",
- "images/button_quit.png",
- "images/button_restart.png",
- ];
- }
-
- /* runs before assets are initialized,
- * used to get data from previous world
- */
- constructor(data) {
- super(data);
- /* save who is AI and who is player */
- this.ai = data.ai;
- this.max_players = data.max_players;
- this.returner = data;
- this.stage_x = data.stage_x;
- this.stage_y = data.stage_y;
- this.mode = data.mode;
- } /* constructor */
- /* initialization */
- start() {
- /* text style */
- this.text_style = new PIXI.TextStyle({
- fill: "#ff0000",
- fontSize: 40,
- });
- /* game data */
- this.current_player = this.max_players;
- this.playing = true;
- /* stage */
- this.stage = [];
- for (let i = 0; i < this.stage_x *this.stage_y; i++) {
- this.stage.push(0);
- }
- /* stage appearence */
- this.stage_sprite = [];
- for (let i = 0; i < this.stage.length; i++) {
- this.stage_sprite[i] = new PIXI.Sprite(
- loader.resources["images/stage_empty.png"].texture
- );
- this.stage_sprite[i].x = width /(this.stage_x+1) *(i%this.stage_x+1);
- this.stage_sprite[i].y = height /(this.stage_y+1) *(Math.floor(i/this.stage_x)+1);
- this.stage_sprite[i].anchor = {x:0.5, y:0.5};
- this.stage_sprite[i].hitArea = new PIXI.Rectangle(0, 0, 100, 100);
- app.stage.addChild(this.stage_sprite[i]);
- }
- /* current player text */
- this.text_cplayer = new PIXI.Text("Hello World",
- this.text_style);
- this.text_cplayer.anchor = {x:0.5, y:1.0};
- this.text_cplayer.x = width/2;
- this.text_cplayer.y = height;
- app.stage.addChild(this.text_cplayer);
- /* restart button (visible when game ends) */
- this.button_restart = new PIXI.Sprite(
- loader.resources["images/button_restart.png"].texture
- );
- this.button_restart.visible = false;
- app.stage.addChild(this.button_restart);
- /* quit button */
- this.button_quit = new PIXI.Sprite(
- loader.resources["images/button_quit.png"].texture
- );
- this.button_quit.anchor = {x:1, y:0};
- this.button_quit.x = width;
- app.stage.addChild(this.button_quit);
- /* AI timer */
- this.ai_timer = 0;
- this.ai_max = 40;
- /* time attack mode depends on value of timer:
- * -1: disabled
- * positive: enabled
- */
- this.timer = -1;
- this.max_timer = 90;
- if (this.mode === "time") {
- this.timer = this.max_timer;
- this.text_timer = new PIXI.Text(
- "timer", this.text_style);
- this.text_timer.anchor = {x:0.5, y:0};
- this.text_timer.x = width/2;
- app.stage.addChild(this.text_timer);
- }
- /* start game */
- this.end_turn();
- }
- /* player touched stage,
- * if touched on empty part,
- * fill it and move to next player
- */
- update() {
- /* timer on time attack */
- if (this.playing && this.timer > 0) {
- this.timer--;
- this.text_timer.text = "time: " +this.timer;
- if (this.timer == 0) {
- this.end_turn();
- }
- }
- /* AI */
- if (this.playing && this.ai[this.current_player-1]) {
- /* advance timer */
- this.ai_timer++;
- /* time to make a move */
- if (this.ai_timer >= this.ai_max) {
- /* find all empty cells */
- let empty_stage = [];
- for (let i = 0; i < this.stage.length; i++) {
- if (this.stage[i] == 0) {
- empty_stage.push(i);
- }
- }
- /* pick one of the cells */
- let target = empty_stage[Math.floor( Math.random() *empty_stage.length )];
- /* make move
- * if for any reason it picks
- * an occupied cell, it will restart
- */
- this.make_move(target);
- /* restart timer for next bot */
- this.ai_timer = 0;
- } /* make move */
- /* ignore all input and updates while AI is playing */
- return;
- } /* AI */
- /* handle input */
- for (let e = 0; e < input.length; e++) {
- /* mouse left click */
- if (input[e].which == 1) {
- /* clicking point */
- let p = new PIXI.Point(input[e].offsetX, input[e].offsetY);
- /* clicked on quit button */
- if (this.button_quit.containsPoint(p)) {
- /* quit to menu */
- return world_list.indexOf(WorldMenu);
- } /* quit menu */
-
- /* game is finished
- * touch only restart and quit button
- */
- if (!this.playing) {
-
- /* restart button */
- if (this.button_restart.containsPoint(p)) {
-
- /* restart this world */
- return world_list.indexOf(WorldTicTacToe);
-
- } /* restart button */
- /* stop any other input */
- break;
- }
- /* through all buttons */
- for (let i = 0; i < this.stage_sprite.length; i++) {
- /* touched button */
- if (this.stage_sprite[i].containsPoint(p)) {
- this.make_move(i);
- /* touch only one button at a time */
- break;
- } /* touched button */
- } /* find button */
- } /* left click */
- } /* handle input */
- } /* update */
- /* check if someone won the game */
- check_victory() {
- /* divine the map into smaller 3x3 boxes, and
- * check them individually
- */
- for (let x = 0; x <= this.stage_x-3; x++)
- for (let y = 0; y <= this.stage_y-3; y++) {
- /* save result as it's the winner or draw
- * if it's 0, ignore it
- */
- let res = this.check_box(x, y);
- if (res != 0) {
- return res;
- }
- }
-
- /* no-one won yet */
- return 0;
- } /* check victory */
- /* checks a 3x3 box on the map, starting from x,y
- * to find a winner
- */
- check_box(x, y) {
- let stage = this.stage;
- let sp = x+(y*this.stage_x);
- let rows = this.stage_x;
- /* check rows-lines */
- for (let i = 0; i < 3; i++) {
- let hor = sp+(i*rows);
- /* horizontal */
- if (stage[hor] == stage[hor+1]
- && stage[hor+1] == stage[hor+2]
- && stage[hor] != 0) {
- return stage[hor];
- }
- let ver = sp+i;
- /* vertical */
- if (stage[ver] == stage[ver+rows]
- && stage[ver+rows] == stage[ver+rows*2]
- && stage[ver] != 0) {
- return stage[ver];
- }
- }
- /* diagonal */
- if (stage[sp] == stage[sp+rows+1]
- && stage[sp+rows+1] == stage[sp+rows*2+2]
- && stage[sp] != 0) {
- return stage[sp];
- }
- /* other diagonal */
- if (stage[sp+2] == stage[sp+rows+1]
- && stage[sp+rows+1] == stage[sp+rows*2]
- && stage[sp+2] != 0) {
- return stage[sp+2];
- }
- /* if all cells are filled, and there is no winner
- * it is a draw
- */
- let draw = true;
- for (let i = 0; i < this.stage_x *this.stage_y; i++) {
- if (this.stage[i] == 0) {
- draw = false;
- break;
- }
- }
- if (draw) {
- return -1;
- }
- /* no-one won yet */
- return 0;
- } /* check box */
- /* ends current player's turn */
- end_turn() {
- /* move to the next player */
- if (++this.current_player > this.max_players) {
- this.current_player = 1;
- }
- /* depending on the value of victory:
- * -1: draw
- * 0: game still running
- * >0: player with that number won
- */
- let v = this.check_victory();
- if (v > 0) {
- this.playing = false;
- this.text_cplayer.text =
- "player " +v +" won!";
- this.button_restart.visible = true;
- return;
- }
- else
- if (v == -1) {
- this.playing = false;
- this.text_cplayer.text = "Draw!";
- this.button_restart.visible = true;
- return;
- }
- /* update current player text */
- let txt_player = this.ai[this.current_player-1] ? "computer" : "player";
- this.text_cplayer.text = txt_player +": " +this.current_player;
- /* in time attack, reset timer for new player */
- if (this.timer >= 0) {
- this.timer = this.max_timer;
- }
- } /* end turn */
-
- /* if i is empty cell,
- * mark it with current player and return true
- * else return false
- */
- make_move(i) {
- /* if square is empty,
- * fill it with current player's index,
- * end turn
- */
- if (this.stage[i] == 0) {
- this.stage[i] = this.current_player;
- this.stage_sprite[i].texture =
- loader.resources["images/stage_p"
- +this.current_player +".png"].texture;
- this.end_turn();
- return true;
- }
- /* not cell changed */
- return false;
- } /* make move */
- } /* world tic-tac-toe */
|