plan project
This commit is contained in:
parent
e2b5173957
commit
d5b56f25c9
7 changed files with 512 additions and 234 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
44
README.md
44
README.md
|
@ -1,9 +1,41 @@
|
||||||
# SEI-CC-4 - Build a Browser Game
|
# Go
|
||||||
## Connect Four
|
#### Minimum Deliverable Product
|
||||||
|
|
||||||
After this repo is cloned, you will be able to syncronize with its most recent commit by running the following two commands:
|
a working game of go for a 9x9 board that
|
||||||
|
* displays well on mobile
|
||||||
|
* initiates a game with suggested handicap and komi according to rank input
|
||||||
|
* * displays how to play in open screen
|
||||||
|
* lets the user know whose turn it is
|
||||||
|
* lets the user know which moves are legal and calculates those accordingly
|
||||||
|
* * logs ko
|
||||||
|
* * implement a search algorithm to avoid moving into dead space
|
||||||
|
* correctly removes captured stones and adds them to capturing player's score
|
||||||
|
* logs game record
|
||||||
|
* maintains a one move game state history for 'undo mismove'
|
||||||
|
* allows players to pass or resign
|
||||||
|
* * ends game upon 2 consecutive passes
|
||||||
|
* calculates estimated score at game end
|
||||||
|
* * compares board groups to most common dead shapes
|
||||||
|
* * allows users to override dead group estimates and submit finalized score to game record
|
||||||
|
* displays game record as string
|
||||||
|
|
||||||
1. `git fetch --all`
|
stretch goals
|
||||||
2. `git reset --hard origin/master`
|
* uses stone placement GUI for resign and pass
|
||||||
|
* converts string to .sgf format
|
||||||
|
* allows users to edit game info mid game
|
||||||
|
* add stone placement sounds
|
||||||
|
|
||||||
Note that running the above commands will completely replace all of the files with those in the repo - **ANY CODE YOU HAVE WRITTEN WILL BE REPLACED**.
|
superstretch goals
|
||||||
|
* allows users to select board size (9x9, 13x13, 19x19)
|
||||||
|
* allows users to load .sgf main lines
|
||||||
|
* allow for responsivity in the form of
|
||||||
|
* * 9x9 games simply stretch with screen size
|
||||||
|
* * larger games allow small displays one click to zoom before running legal move calculations and move placement
|
||||||
|
|
||||||
|
<!-- describe go with images of game-->
|
||||||
|
|
||||||
|
<!-- List of technologies used -->
|
||||||
|
|
||||||
|
<!-- How to play, link to deploy -->
|
||||||
|
|
||||||
|
<!-- roadmap -->
|
49
css/main.css
49
css/main.css
|
@ -1,42 +1,15 @@
|
||||||
*, *::before, *::after {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
.full-screen {
|
||||||
font-family: Montserrat;
|
/* positioning will be absolue */
|
||||||
height: 100vh;
|
/* will take up whole screen */
|
||||||
margin: 0;
|
/* background will be ~0.5 opacity */
|
||||||
display: flex;
|
/* grid-areas
|
||||||
flex-direction: column;
|
"game-info *4" <-date, komi, handicap
|
||||||
justify-content: center;
|
"b-player-info*2 w-player-info*2" <- name, rank, rank-certainty
|
||||||
align-items: center;
|
"record record record options" <- displays numbered record (stretch!), new game, get game record(stretch!)
|
||||||
}
|
pre-game record will display instructions
|
||||||
|
*/
|
||||||
section.markers {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(7, 10vmin);
|
|
||||||
grid-gap: 1vmin;
|
|
||||||
margin-bottom: 1vmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.markers div {
|
|
||||||
border-top: 5vmin solid lightgrey;
|
|
||||||
border-left: 5vmin solid transparent;
|
|
||||||
border-right: 5vmin solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.markers div:hover {
|
|
||||||
border-top-color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.board {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(7, 10vmin);
|
|
||||||
grid-template-rows: repeat(6, 10vmin);
|
|
||||||
grid-gap: 1vmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.board div {
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid grey;
|
|
||||||
}
|
}
|
366
css/reset.css
Normal file
366
css/reset.css
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0-modified | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure to set some focus styles for accessibility */
|
||||||
|
:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=search]::-webkit-search-cancel-button,
|
||||||
|
input[type=search]::-webkit-search-decoration,
|
||||||
|
input[type=search]::-webkit-search-results-button,
|
||||||
|
input[type=search]::-webkit-search-results-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=search] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
-moz-box-sizing: content-box;
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
vertical-align: top;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio,
|
||||||
|
canvas,
|
||||||
|
video {
|
||||||
|
display: inline-block;
|
||||||
|
*display: inline;
|
||||||
|
*zoom: 1;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent modern browsers from displaying `audio` without controls.
|
||||||
|
* Remove excess height in iOS 5 devices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.
|
||||||
|
* Known issue: no IE 6 support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using
|
||||||
|
* `em` units.
|
||||||
|
* 2. Prevent iOS text size adjust after orientation change, without disabling
|
||||||
|
* user zoom.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
-ms-text-size-adjust: 100%; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address `outline` inconsistency between Chrome and other browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a:focus {
|
||||||
|
outline: thin dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Improve readability when focused and also mouse hovered in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a:active,
|
||||||
|
a:hover {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.
|
||||||
|
* 2. Improve image quality when scaled in IE 7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: 0; /* 1 */
|
||||||
|
-ms-interpolation-mode: bicubic; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct margin displayed oddly in IE 6/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define consistent border, margin, and padding.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #c0c0c0;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: 0.35em 0.625em 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct color not being inherited in IE 6/7/8/9.
|
||||||
|
* 2. Correct text not wrapping in Firefox 3.
|
||||||
|
* 3. Correct alignment displayed oddly in IE 6/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
border: 0; /* 1 */
|
||||||
|
padding: 0;
|
||||||
|
white-space: normal; /* 2 */
|
||||||
|
*margin-left: -7px; /* 3 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct font size not being inherited in all browsers.
|
||||||
|
* 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,
|
||||||
|
* and Chrome.
|
||||||
|
* 3. Improve appearance and consistency in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
margin: 0; /* 2 */
|
||||||
|
vertical-align: baseline; /* 3 */
|
||||||
|
*vertical-align: middle; /* 3 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address Firefox 3+ setting `line-height` on `input` using `!important` in
|
||||||
|
* the UA stylesheet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||||
|
* All other form control elements do not inherit `text-transform` values.
|
||||||
|
* Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.
|
||||||
|
* Correct `select` style inheritance in Firefox 4+ and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||||
|
* and `video` controls.
|
||||||
|
* 2. Correct inability to style clickable `input` types in iOS.
|
||||||
|
* 3. Improve usability and consistency of cursor style between image-type
|
||||||
|
* `input` and others.
|
||||||
|
* 4. Remove inner spacing in IE 7 without affecting normal text inputs.
|
||||||
|
* Known issue: inner spacing remains in IE 6.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
html input[type="button"], /* 1 */
|
||||||
|
input[type="reset"],
|
||||||
|
input[type="submit"] {
|
||||||
|
-webkit-appearance: button; /* 2 */
|
||||||
|
cursor: pointer; /* 3 */
|
||||||
|
*overflow: visible; /* 4 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-set default cursor for disabled elements.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button[disabled],
|
||||||
|
html input[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Address box sizing set to content-box in IE 8/9.
|
||||||
|
* 2. Remove excess padding in IE 8/9.
|
||||||
|
* 3. Remove excess padding in IE 7.
|
||||||
|
* Known issue: excess padding remains in IE 6.
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type="checkbox"],
|
||||||
|
input[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
*height: 13px; /* 3 */
|
||||||
|
*width: 13px; /* 3 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
|
||||||
|
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
|
||||||
|
* (include `-moz` to future-proof).
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
-moz-box-sizing: content-box;
|
||||||
|
-webkit-box-sizing: content-box; /* 2 */
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove inner padding and search cancel button in Safari 5 and Chrome
|
||||||
|
* on OS X.
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type="search"]::-webkit-search-cancel-button,
|
||||||
|
input[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove inner padding and border in Firefox 3+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
input::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove default vertical scrollbar in IE 6/7/8/9.
|
||||||
|
* 2. Improve readability and alignment in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto; /* 1 */
|
||||||
|
vertical-align: top; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove most spacing between table cells.
|
||||||
|
*/
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::-moz-selection {
|
||||||
|
background: #b3d4fc;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background: #b3d4fc;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chromeframe {
|
||||||
|
margin: 0.2em 0;
|
||||||
|
background: #ccc;
|
||||||
|
color: #000;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
}
|
BIN
go wireframe.tif
Normal file
BIN
go wireframe.tif
Normal file
Binary file not shown.
84
index.html
84
index.html
|
@ -4,71 +4,27 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<title>Connect Four</title>
|
<link rel="stylesheet" href="css/reset.css" type="stylesheet">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
|
<link rel="stylesheet" href="css/main.css" type="stylesheet">
|
||||||
<link rel="stylesheet" href="css/main.css">
|
<script src="js/main.js"></script>
|
||||||
<script defer src="js/main.js"></script>
|
<title>Go Cats</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>CONNECT FOUR</h1>
|
<div id="menu" class="full-screen">
|
||||||
<h2 id="msg"></h2>
|
<!-- for displaying new game screen and status during game -->
|
||||||
<section class="markers">
|
</div>
|
||||||
<div id="col0"></div>
|
<!-- may need add'l .full-screen or other div for board overlay -->
|
||||||
<div id="col1"></div>
|
<content>
|
||||||
<div id="col2"></div>
|
<div id="white-pos" class="player-pos">
|
||||||
<div id="col3"></div>
|
<div id="white-bowl" class="bowl"></div>
|
||||||
<div id="col4"></div>
|
<div id="white-caps" class="caps"></div>
|
||||||
<div id="col5"></div>
|
</div>
|
||||||
<div id="col6"></div>
|
<div id="board"></div>
|
||||||
</section>
|
<div id="black-pos" class="player-pos">
|
||||||
<section class="board">
|
<div id="black-bowl" class="bowl"></div>
|
||||||
<div id="c0r5"></div>
|
<div id="black-caps" class="caps"></div>
|
||||||
<div id="c1r5"></div>
|
<div id="kifu"></div>
|
||||||
<div id="c2r5"></div>
|
</div>
|
||||||
<div id="c3r5"></div>
|
</content>
|
||||||
<div id="c4r5"></div>
|
|
||||||
<div id="c5r5"></div>
|
|
||||||
<div id="c6r5"></div>
|
|
||||||
|
|
||||||
<div id="c0r4"></div>
|
|
||||||
<div id="c1r4"></div>
|
|
||||||
<div id="c2r4"></div>
|
|
||||||
<div id="c3r4"></div>
|
|
||||||
<div id="c4r4"></div>
|
|
||||||
<div id="c5r4"></div>
|
|
||||||
<div id="c6r4"></div>
|
|
||||||
|
|
||||||
<div id="c0r3"></div>
|
|
||||||
<div id="c1r3"></div>
|
|
||||||
<div id="c2r3"></div>
|
|
||||||
<div id="c3r3"></div>
|
|
||||||
<div id="c4r3"></div>
|
|
||||||
<div id="c5r3"></div>
|
|
||||||
<div id="c6r3"></div>
|
|
||||||
|
|
||||||
<div id="c0r2"></div>
|
|
||||||
<div id="c1r2"></div>
|
|
||||||
<div id="c2r2"></div>
|
|
||||||
<div id="c3r2"></div>
|
|
||||||
<div id="c4r2"></div>
|
|
||||||
<div id="c5r2"></div>
|
|
||||||
<div id="c6r2"></div>
|
|
||||||
|
|
||||||
<div id="c0r1"></div>
|
|
||||||
<div id="c1r1"></div>
|
|
||||||
<div id="c2r1"></div>
|
|
||||||
<div id="c3r1"></div>
|
|
||||||
<div id="c4r1"></div>
|
|
||||||
<div id="c5r1"></div>
|
|
||||||
<div id="c6r1"></div>
|
|
||||||
|
|
||||||
<div id="c0r0"></div>
|
|
||||||
<div id="c1r0"></div>
|
|
||||||
<div id="c2r0"></div>
|
|
||||||
<div id="c3r0"></div>
|
|
||||||
<div id="c4r0"></div>
|
|
||||||
<div id="c5r0"></div>
|
|
||||||
<div id="c6r0"></div>
|
|
||||||
</section>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
197
js/main.js
197
js/main.js
|
@ -1,132 +1,83 @@
|
||||||
/*----- constants -----*/
|
// global constants declared
|
||||||
const COLORS = {
|
|
||||||
'0': 'white',
|
|
||||||
'1': 'purple',
|
|
||||||
'-1': 'lime'
|
|
||||||
};
|
|
||||||
|
|
||||||
/*----- app's state (variables) -----*/
|
// boardState, lastState, overlay (copy of boardState holding pre-move object, game end group state)
|
||||||
let board, turn, winner;
|
// bCaptures, wCaptures, gameInfo object, playerInfo object, turn, pass, gameRecord,
|
||||||
|
// handicapStones, deadShapes{}
|
||||||
|
|
||||||
/*----- cached element references -----*/
|
|
||||||
const msgEl = document.getElementById('msg');
|
|
||||||
|
|
||||||
/*----- event listeners -----*/
|
// define initial game state
|
||||||
document.querySelector('section.markers')
|
|
||||||
.addEventListener('click', handleClick);
|
|
||||||
|
|
||||||
/*----- functions -----*/
|
// define boardState and overlay as 2d 9x9 arrays
|
||||||
init();
|
// boardState accepts values of 0, 1, -1
|
||||||
|
// overlay accepts values of 0, 1, -1, 'k', 'd', 'chk', 'hold', 'l', 'x'
|
||||||
|
// 'k' represents komi, in-game integers represent move previews,
|
||||||
|
// 'chk', 'hold', 'x' and 'l' represent points checked during checkLegalMove run
|
||||||
|
// game-end integer represent points of territory, 'd' represents dame,
|
||||||
|
|
||||||
function init() {
|
|
||||||
board = [
|
|
||||||
[0, 0, 0, 0, 0, 0], // column 1 (index 0)
|
|
||||||
[0, 0, 0, 0, 0, 0], // column 2 (index 1)
|
|
||||||
[0, 0, 0, 0, 0, 0], // column 3 (index 2)
|
|
||||||
[0, 0, 0, 0, 0, 0], // column 4 (index 3)
|
|
||||||
[0, 0, 0, 0, 0, 0], // column 5 (index 4)
|
|
||||||
[0, 0, 0, 0, 0, 0], // column 6 (index 5)
|
|
||||||
[0, 0, 0, 0, 0, 0], // column 7 (index 6)
|
|
||||||
];
|
|
||||||
turn = 1;
|
|
||||||
winner = null; // 1, -1, null (no winner), 'T' (tie)
|
|
||||||
render();
|
|
||||||
}
|
|
||||||
|
|
||||||
function render() {
|
// cached elements
|
||||||
// Render the board
|
// store #menu for displaying game info
|
||||||
board.forEach(function(colArr, colIdx) {
|
// store
|
||||||
// hide/show the column's marker depending if there are 0's or not
|
|
||||||
let marker = document.getElementById(`col${colIdx}`);
|
|
||||||
// <conditional exp> ? <truthy thing to return> : <falsey thing to return>;
|
|
||||||
// This is a ternary expression that replaces the if/else below it.
|
|
||||||
marker.style.visibility = colArr.indexOf(0) === -1 ? 'hidden' : 'visible';
|
|
||||||
// if (colArr.indexOf(0) === -1) {
|
|
||||||
// marker.style.visibility = 'hidden';
|
|
||||||
// } else {
|
|
||||||
// marker.style.visibility = 'visible';
|
|
||||||
// }
|
|
||||||
colArr.forEach(function(cell, rowIdx) {
|
|
||||||
let div = document.getElementById(`c${colIdx}r${rowIdx}`);
|
|
||||||
div.style.backgroundColor = COLORS[cell];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// Render the message
|
|
||||||
if (winner) {
|
|
||||||
if (winner === 'T') {
|
|
||||||
msgEl.textContent = "It's a Tie!";
|
|
||||||
} else {
|
|
||||||
msgEl.innerHTML = `<span style="color:${COLORS[winner]}">${COLORS[winner].toUpperCase()}</span> Wins!`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
msgEl.innerHTML = `<span style="color:${COLORS[turn]}">${COLORS[turn].toUpperCase()}</span>'s Turn`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClick(evt) {
|
|
||||||
// get index of column's marker clicked
|
|
||||||
let idx = parseInt(evt.target.id.replace('col', ''));
|
|
||||||
// make sure the MARKER was clicked
|
|
||||||
if (isNaN(idx) || winner) return;
|
|
||||||
// obtain the actual column array in board array
|
|
||||||
let colArr = board[idx];
|
|
||||||
// get the index of the first 0 in the col array
|
|
||||||
let rowIdx = colArr.indexOf(0);
|
|
||||||
// if the col is full, there are no zeroes, therefore
|
|
||||||
// indexOf returns -1.
|
|
||||||
// Do nothing if no zeroes available (col full)
|
|
||||||
if (rowIdx === -1) return;
|
|
||||||
// update the col array (within the board) with
|
|
||||||
// the player whose turn it is
|
|
||||||
colArr[rowIdx] = turn;
|
|
||||||
// flip turns from 1 to -1; -1 to 1
|
|
||||||
turn *= -1;
|
|
||||||
// update the winner
|
|
||||||
winner = getWinner();
|
|
||||||
render();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWinner() {
|
// set event listeners
|
||||||
// return the winner, 'T' or null
|
// input listeners for player names, ranks, rank certainty (editable during game)
|
||||||
let winner = null;
|
//input lister for handicap + komi (only editable pre-game)
|
||||||
// using a for loop because we want to stop looping if we find a winner
|
// ::hover-over on board to preview move (with legal move logic)
|
||||||
for (let colIdx = 0; colIdx < board.length; colIdx++) {
|
// click on board to play move
|
||||||
// check if any cells in the col lead to a winner
|
// ::hover-over on either bowl for pass, one-level undo options (CSS implementation)
|
||||||
winner = checkCol(colIdx);
|
// click on menu items
|
||||||
// done if winner is found, no reason to keep looking
|
// click on kifu to display game menu
|
||||||
if (winner) break;
|
|
||||||
}
|
|
||||||
return winner;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkCol(colIdx) {
|
// functions
|
||||||
let winner = null;
|
// initialize game
|
||||||
for (let rowIdx = 0; rowIdx < board[colIdx].length; rowIdx++) {
|
// set handicap stones
|
||||||
// using the logical OR operator (||) prevents the checks to the right
|
// render
|
||||||
// from ever running if a winner is found. For example, if checkUp returns
|
// render board
|
||||||
// a truthy value, checkRight and the checkDiag will never be called
|
//render moves
|
||||||
winner = checkUp(colIdx, rowIdx) || checkRight(colIdx, rowIdx) || checkDiag(colIdx, rowIdx, 1) || checkDiag(colIdx, rowIdx, -1);
|
//render preview
|
||||||
if (winner) break;
|
// render captures
|
||||||
}
|
// render player turn marker
|
||||||
return winner;
|
// game-end
|
||||||
}
|
// render dead group suggestion
|
||||||
|
// render territory counts
|
||||||
function checkUp(colIdx, rowIdx) {
|
// checkLegalMove
|
||||||
// boundary check (can't check up if rowIdx is greater than 2)
|
// clear overlay
|
||||||
if (rowIdx > 2) return null;
|
// if move is not '0', move is illegal (opposing player or 'k' for ko)
|
||||||
const colArr = board[colIdx];
|
// iterate through neighboring points in clockwise order
|
||||||
// ternary expression deluxe!
|
// if anyone is '0' move is legal - call render preview
|
||||||
return ( Math.abs(colArr[rowIdx] + colArr[rowIdx + 1] + colArr[rowIdx + 2] + colArr[rowIdx + 3]) === 4 ) ? colArr[rowIdx] : null;
|
// if neighboring point is opposing player
|
||||||
}
|
// cycle through opposing player group marking points as overlay: 'chk' when checked and
|
||||||
|
// overlay: 'hold' if they are neighboring points of opposing player color
|
||||||
function checkRight(colIdx, rowIdx) {
|
// if any neighboring point is '0' terminate cycle and move to next neighboring point of original move
|
||||||
if (colIdx > 3) return null;
|
// if there are unchecked points of 'hold' return
|
||||||
return ( Math.abs(board[colIdx][rowIdx] + board[colIdx + 1][rowIdx] + board[colIdx + 2][rowIdx] + board[colIdx + 3][rowIdx]) === 4 ) ? board[colIdx][rowIdx] : null;
|
// if no boardState: 0 points, move is legal overlay: 'l'
|
||||||
}
|
// set all 'chk' to 'x' to represent stones that will be captured upon move
|
||||||
|
// if neighboring point is player's
|
||||||
// Notice the extra vertOffset parameter for determining whether checking up or down vertically
|
// cycle through player group marking points as overlay: 'chk' || 'hold'
|
||||||
function checkDiag(colIdx, rowIdx, vertOffset) {
|
// if any neighboring point is '0' ternminate cycle and mark point as 'l'
|
||||||
// lot's of boundaries to check
|
// set move
|
||||||
if (colIdx > 3 || (vertOffset > 0 && rowIdx > 2) || (vertOffset < 0 && rowIdx < 3)) return null;
|
// if checkLegalMove has returned '0' i2llegal move message?
|
||||||
return ( Math.abs(board[colIdx][rowIdx] + board[colIdx + 1][rowIdx + vertOffset] + board[colIdx + 2][rowIdx + (vertOffset * 2)] + board[colIdx + 3][rowIdx + (vertOffset * 3)]) === 4 ) ? board[colIdx][rowIdx] : null;
|
// if move state is 'l'
|
||||||
}
|
// push boardState to lastState
|
||||||
|
// push 'l' move to boardState
|
||||||
|
// resolve captures
|
||||||
|
// for all 'x' in overlay
|
||||||
|
// count number and add to playerCaptures
|
||||||
|
// set boardState to '0'
|
||||||
|
// pass--
|
||||||
|
// push move to game record
|
||||||
|
// game record: [ 0: handicapStones Obj, 1: 1stMove([moveState[],moveState[][])]
|
||||||
|
// pass() pass++ and player turn to other player
|
||||||
|
// gameEnd when pass = 2
|
||||||
|
// search empty spaces on board for deadShapes
|
||||||
|
// compare spaces to rotations of deadShapes[...]
|
||||||
|
// 'd' if empty spaces
|
||||||
|
// return dead group suggestion
|
||||||
|
// users can flip status of any dead group overlay( 1, -1 )
|
||||||
|
// confirm state
|
||||||
|
// calculate score = points in overlay for each player + captures
|
||||||
|
// render final board state with dead groups removed
|
||||||
|
// log game record
|
||||||
|
// stringify according to .sgf format
|
||||||
|
// log as text
|
||||||
|
|
Loading…
Reference in a new issue