Advertisement
airevent

пример игры го на JavaScript

Mar 11th, 2013
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //
  2.  
  3. var Goban = function( conf ) {
  4.     this.parent = $(document.body);
  5.     this.lines = 19;
  6.     this.cellwh = 38;
  7.     this.palette = 1;
  8.     this.need_chars = true;
  9.  
  10.     this.configure(conf);
  11. };
  12.  
  13. var c = Goban;
  14. var p = c.prototype;
  15.  
  16. c.colors = ["#000",0,0,0,0,0,"#FFF"];
  17. c.chars = "*ABCDEFGHJKLMNOPQRSTUVWXYZ".split("");
  18.  
  19. c.ntoc = function( n ) {
  20.     return n < c.chars.length ? c.chars[n] : n-25;
  21. };
  22.  
  23.  
  24.  
  25. p.build = function() {
  26.     this.draw_ban();
  27.     this.draw_lines();
  28.     this.draw_dots();
  29.     this.draw_chars();
  30.     this.set_palette(this.palette);
  31.     this.init_grid();
  32.     this.bind_events();
  33. };
  34.  
  35.  
  36.  
  37. p.destroy = function() {
  38.     this.ban.remove();
  39. };
  40.  
  41.  
  42.  
  43. p.configure = function( conf ) {
  44.     $.extend(this, conf);
  45.  
  46.     this.lines = this.lines < 3 ? 3 : (this.lines > 99 ? 99 : this.lines);
  47.     this.padding = Math.ceil(this.cellwh/2+6);
  48.     if ( this.need_chars ) this.padding += 18;
  49.     this.stonewh = this.cellwh-2;
  50.     if ( this.stonewh%2==0 ) this.stonewh--;
  51. };
  52.  
  53.  
  54.  
  55. p.draw_ban = function() {
  56.     this.ban = $("<div/>").css({
  57.         width: this.padding * 2 + this.lines + this.cellwh * (this.lines-1),
  58.         height: this.padding * 2 + this.lines + this.cellwh * (this.lines-1),
  59.     }).addClass("Goban").appendTo(this.parent);
  60.  
  61.     this.ban.disableSelection();
  62.     this.ban.on("contextmenu", function(){return false;});
  63. };
  64.  
  65.  
  66.  
  67. p.draw_lines = function() {
  68.     for ( var i=1; i<this.lines; ++i ) {
  69.         $("<div/>").css({
  70.             top: this.padding,
  71.             left: this.padding,
  72.             width: this.cellwh * i + i-1,
  73.             height: this.cellwh * i + i-1,
  74.         }).addClass("line").appendTo(this.ban).
  75.         attr("i",i).attr("tl",true);
  76.  
  77.         $("<div/>").css({
  78.             bottom: this.padding,
  79.             right: this.padding,
  80.             width: this.cellwh * i + i-1,
  81.             height: this.cellwh * i + i-1,
  82.         }).addClass("line").appendTo(this.ban).
  83.         attr("i",i);
  84.     }
  85. };
  86.  
  87.  
  88.  
  89. p.draw_dots = function() {
  90.     var n = this.lines;
  91.  
  92.     if ( n==5 ) {
  93.         this.add_dot(n/2, n/2);
  94.     } else if ( n>=7 ) {
  95.         var step = n<=9 ? 2 : 3;
  96.         this.add_dot(1+step, 1+step);
  97.         this.add_dot(n-step, 1+step);
  98.         this.add_dot(1+step, n-step);
  99.         this.add_dot(n-step, n-step);
  100.         if ( n>=13 && n%2 ) {
  101.             this.add_dot(n/2, n/2);
  102.             this.add_dot(n/2, 1+step);
  103.             this.add_dot(n/2, n-step);
  104.             this.add_dot(1+step, n/2);
  105.             this.add_dot(n-step, n/2);
  106.         }
  107.     }
  108. };
  109.  
  110.  
  111.  
  112. p.add_dot = function( x, y ) {
  113.     x = Math.ceil(x);
  114.     y = Math.ceil(y);
  115.     $("<div/>").addClass("dot").appendTo(this.ban).
  116.     attr("x",x).attr("y",y);
  117. };
  118.  
  119.  
  120.  
  121. p.draw_chars = function() {
  122.     if ( !this.need_chars ) return;
  123.  
  124.     for ( var i=1; i<=this.lines; ++i ) {
  125.         $("<div/>").text(i).css({
  126.             bottom: this.padding - 6 + (i-1) * this.cellwh + i-1,
  127.             left: 4,
  128.         }).addClass("char").appendTo(this.ban).
  129.         attr("i",i).attr("btm",true);
  130.         $("<div/>").text(i).css({
  131.             bottom: this.padding - 6 + (i-1) * this.cellwh + i-1,
  132.             right: 4,
  133.         }).addClass("char").appendTo(this.ban).
  134.         attr("i",i).attr("btm",true);
  135.         $("<div/>").text(c.ntoc(i)).css({
  136.             top: 5,
  137.             left: this.padding - 8 + (i-1) * this.cellwh + i-1,
  138.         }).addClass("char").appendTo(this.ban).
  139.         attr("i",i);
  140.         $("<div/>").text(c.ntoc(i)).css({
  141.             bottom: 5,
  142.             left: this.padding - 8 + (i-1) * this.cellwh + i-1,
  143.         }).addClass("char").appendTo(this.ban).
  144.         attr("i",i);
  145.     }
  146. };
  147.  
  148.  
  149.  
  150. p.resize = function( conf ) {
  151.     var s,x,y;
  152.     var self = this;
  153.  
  154.     this.configure(conf);
  155.  
  156.     var chars = this.ban.children(".char");
  157.     if ( this.need_chars && chars.length==0 ) {
  158.         this.draw_chars();
  159.         this.set_palette(this.palette);
  160.     }
  161.     chars.css("display", this.need_chars ? "block" : "none");
  162.  
  163.     this.ban.css({
  164.         width: this.padding * 2 + this.lines + this.cellwh * (this.lines-1),
  165.         height: this.padding * 2 + this.lines + this.cellwh * (this.lines-1),
  166.     });
  167.  
  168.     this.ban.children(".line").each(function() {
  169.         var o = $(this);
  170.         var i = parseInt(o.attr("i"));
  171.         var tl = o.attr("tl");
  172.         var css = {
  173.             width: self.cellwh * i + i-1,
  174.             height: self.cellwh * i + i-1,
  175.         };
  176.         css[tl?"top":"bottom"] = self.padding;
  177.         css[tl?"left":"right"] = self.padding;
  178.         o.css(css);
  179.     });
  180.  
  181.     this.ban.children(".dot").each(function() {
  182.         var o = $(this);
  183.         var x = parseInt(o.attr("x"));
  184.         var y = parseInt(o.attr("y"));
  185.         var color = c.colors[self.palette] || c.colors[0];
  186.         var indent = color==c.colors[0] ? 2 : 3;
  187.         var wh = color==c.colors[0] ? 5 : 7;
  188.         o.css({
  189.             top: self.padding - indent + (y-1)*self.cellwh + y-1,
  190.             left: self.padding - indent + (x-1)*self.cellwh + x-1,
  191.             width: wh,
  192.             height: wh,
  193.             borderRadius: wh,
  194.         });
  195.     });
  196.  
  197.     this.ban.children(".char").each(function() {
  198.         var o = $(this);
  199.         var i = parseInt(o.attr("i"));
  200.         var btm = o.attr("btm");
  201.         var css = {};
  202.         if ( btm ) {
  203.             css.bottom = self.padding - 6 + (i-1) * self.cellwh + i-1;
  204.         } else {
  205.             css.left = self.padding - 8 + (i-1) * self.cellwh + i-1;
  206.         }
  207.         o.css(css);
  208.     });
  209.  
  210.     for ( x=0; x<this.lines; ++x ) {
  211.         for ( y=0; y<this.lines; ++y ) {
  212.             s = this.grid[x][y];
  213.             if ( s ) {
  214.                 var shadow = s.color=="w" ?
  215.                     (this.stonewh/3)+"px #AAA":
  216.                     this.stonewh+"px #000";
  217.                 s.obj.css({
  218.                     top: this.padding - this.stonewh/2 + y*this.cellwh + y,
  219.                     left: this.padding - this.stonewh/2 + x*this.cellwh + x,
  220.                     width: this.stonewh,
  221.                     height: this.stonewh,
  222.                     borderRadius: this.stonewh,
  223.                     boxShadow:  "2px 2px 2px rgba(0,0,0,0.5), " +
  224.                                 "inset 0 0 "+shadow,
  225.                 });
  226.             }
  227.         }
  228.     }
  229. };
  230.  
  231.  
  232.  
  233. p.set_palette = function( palette ) {
  234.     this.palette = palette;
  235.     var color = c.colors[palette] || c.colors[0];
  236.  
  237.     this.ban.css("background-image", palette>0?"url(img/bg"+palette+".jpg)":"none");
  238.     this.ban.children(".line").css("border-color", color);
  239.     this.ban.children(".dot").css({ background:color, boxShadow:"0 0 1px "+color });
  240.     this.ban.children(".char").css("color", color);
  241.  
  242.     var self = this;
  243.     this.ban.children(".dot").each(function() {
  244.         var o = $(this);
  245.         var x = parseInt(o.attr("x"));
  246.         var y = parseInt(o.attr("y"));
  247.         var color = c.colors[self.palette] || c.colors[0];
  248.         var indent = color==c.colors[0] ? 2 : 3;
  249.         var wh = color==c.colors[0] ? 5 : 7;
  250.         o.css({
  251.             top: self.padding - indent + (y-1)*self.cellwh + y-1,
  252.             left: self.padding - indent + (x-1)*self.cellwh + x-1,
  253.             width: wh,
  254.             height: wh,
  255.             borderRadius: wh,
  256.         });
  257.     });
  258. };
  259.  
  260.  
  261.  
  262. p.bind_events = function() {
  263.     var self = this;
  264.  
  265.     this.ban.mousedown(function( e ) {
  266.         var x = Math.round((e.pageX - self.ban.offset().left - self.padding) / (self.cellwh+1));
  267.         var y = Math.round((e.pageY - self.ban.offset().top - self.padding) / (self.cellwh+1));
  268.         if ( e.which===1 ) {
  269.             self.add_stone(x, y, self.game.turn);
  270.         }
  271.     });
  272. };
  273.  
  274.  
  275.  
  276. p.init_grid = function() {
  277.     var x,y;
  278.     this.grid = [];
  279.     for ( x=0; x<this.lines; ++x ) {
  280.         this.grid[x] = [];
  281.         for ( y=0; y<this.lines; ++y ) {
  282.             this.grid[x][y] = false;
  283.         }
  284.     }
  285. };
  286.  
  287.  
  288.  
  289. p.isongrid = function( x, y ) {
  290.     return ( x>=0 && x<this.lines && y>=0 && y<this.lines );
  291. };
  292.  
  293.  
  294.  
  295. p.add_stone = function( x, y, color ) {
  296.     if ( !this.isongrid(x,y) ) {
  297.         return;//this.game.onerror("камни нельзя размещать за пределами сетки");
  298.     }
  299.  
  300.     if ( this.grid[x][y] ) {
  301.         return this.game.onerror("камни нельзя размещать друг на друге");
  302.     }
  303.  
  304.     var bgcolor = color=="w" ? "#FFF" : "#454545";
  305.     var shadow = color=="w" ?
  306.         (this.stonewh/3)+"px #AAA":
  307.         this.stonewh+"px #000";
  308.  
  309.     var obj = $("<div/>").css({
  310.         top: this.padding - this.stonewh/2 + y*this.cellwh + y,
  311.         left: this.padding - this.stonewh/2 + x*this.cellwh + x,
  312.         width: this.stonewh,
  313.         height: this.stonewh,
  314.         borderRadius: this.stonewh,
  315.         background: bgcolor,
  316.         boxShadow:  "2px 2px 2px rgba(0,0,0,0.5), " +
  317.                     "inset 0 0 "+shadow,
  318.     }).addClass("stone").appendTo(this.ban);
  319.  
  320.     var stone = { x:x, y:y, color:color, obj:obj, info:{} };
  321.     this.grid[x][y] = stone;
  322.  
  323.     var rollback_reason = this.remove_dead_stones(stone);
  324.  
  325.     if ( rollback_reason ) {
  326.         this.game.onerror(rollback_reason);
  327.         this.grid[x][y] = false;
  328.         obj.remove();
  329.     } else {
  330.         this.game.onturn(color);
  331.     }
  332. };
  333.  
  334.  
  335.  
  336. p.clean_stones = function() {
  337.     var s,x,y;
  338.     for ( x=0; x<this.lines; ++x ) {
  339.         for ( y=0; y<this.lines; ++y ) {
  340.             s = this.grid[x][y];
  341.             if ( s ) s.info = {};
  342.         }
  343.     }
  344. };
  345.  
  346.  
  347.  
  348. p.add_lps_enemy = function( lps_enemies, lps, x, y ) {
  349.     if ( this.isongrid(x,y) ) {
  350.         var s = this.grid[x][y];
  351.         if ( s && s.color != lps.color ) {
  352.             lps_enemies.push(s);
  353.             s.info.lps_enemy_n = lps_enemies.length; // нумерация с 1 !!!!
  354.         }
  355.     }
  356. };
  357.  
  358.  
  359.  
  360. // rollback: false - no, text - true
  361. p.remove_dead_stones = function( lps ) { // lps = last placed stone
  362.     var s,x,y;
  363.     var dead;
  364.     var lps_enemies = []; // вражеские камни, лежащие вплотную к lps, которые нужно проверить на жизнеспособность
  365.     var lps_enemies_killed = 0;
  366.  
  367.     this.clean_stones();
  368.  
  369.     // найти все вражеские камни, лежащие вплотную к lps
  370.     x=lps.x; y=lps.y;
  371.     this.add_lps_enemy(lps_enemies, lps, x+1, y);
  372.     this.add_lps_enemy(lps_enemies, lps, x-1, y);
  373.     this.add_lps_enemy(lps_enemies, lps, x, y+1);
  374.     this.add_lps_enemy(lps_enemies, lps, x, y-1);
  375.  
  376.     while ( lps_enemies.length > 0 ) {
  377.         s = lps_enemies.pop();
  378.         if ( !s ) continue;
  379.         dead = this.check_s_life(s, lps_enemies);
  380.         if ( dead ) {
  381.             lps_enemies_killed++;
  382.             this.kill_group(dead);
  383.         }
  384.     }
  385.  
  386.     if ( lps_enemies_killed==0 ) {
  387.         dead = this.check_s_life(lps, lps_enemies);
  388.         if ( dead ) {
  389.             if ( !this.game.allow_suicide ) {
  390.                 return "суицид запрещён правилами";
  391.             } else if ( dead.length == 1 ) {
  392.                 return "ход не имеет смысла: камень будет сразу съеден";
  393.             } else {
  394.                 this.kill_group(dead);
  395.             }
  396.         }
  397.     }
  398. };
  399.  
  400.  
  401.  
  402. p.kill_group = function( group ) {
  403.     for ( var i=0; i<group.length; ++i ) {
  404.         var s = group[i];
  405.         this.grid[s.x][s.y] = false;
  406.         this.game.oncapture(s);
  407.         s.obj.remove();
  408.     }
  409. };
  410.  
  411.  
  412.  
  413. // проверить жизнеспособность группы, содержащей камень s
  414. // удалить если нет дыханий
  415. // вернуть инфу о том жива ли группа
  416. p.check_s_life = function( s, lps_enemies ) {
  417.     var s,x,y;
  418.     var dame = 0;
  419.     var friends = [];
  420.     var dead = []; // полный список, если нужно будет убить
  421.  
  422.     s.info.is_friend = true;
  423.     friends.push(s);
  424.     dead.push(s);
  425.  
  426.     while ( friends.length > 0 ) {
  427.         s = friends.pop();
  428.         x=s.x; y=s.y;
  429.         dame += this.check_s_near(lps_enemies, friends, dead, s, x+1, y);
  430.         dame += this.check_s_near(lps_enemies, friends, dead, s, x-1, y);
  431.         dame += this.check_s_near(lps_enemies, friends, dead, s, x, y+1);
  432.         dame += this.check_s_near(lps_enemies, friends, dead, s, x, y-1);
  433.     }
  434.  
  435.     if ( dame > 0 ) dead = false;
  436.     return dead;
  437. };
  438.  
  439.  
  440.  
  441. p.check_s_near = function( lps_enemies, friends, dead, s, x, y ) {
  442.     if ( !this.isongrid(x,y) ) return 0; // border
  443.     var friend = this.grid[x][y];
  444.     if ( !friend ) return 1; // empty, +1 dame
  445.     if ( s.color != friend.color ) return 0; // enemy
  446.  
  447.     if ( friend.info.lps_enemy_n ) {
  448.         lps_enemies[friend.info.lps_enemy_n-1] = false;
  449.     }
  450.  
  451.     if ( !friend.info.is_friend ) {
  452.         friend.info.is_friend = true;
  453.         friends.push(friend);
  454.         dead.push(friend);
  455.     }
  456.  
  457.     return 0; // friend
  458. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement