diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..ba3b77f Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md index 8af0a82..682c6c6 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,41 @@ -# SEI-CC-4 - Build a Browser Game -## Connect Four +# Go +#### 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` -2. `git reset --hard origin/master` +stretch goals +* 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 + +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 -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**. \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/css/main.css b/css/main.css index 315a539..7826762 100644 --- a/css/main.css +++ b/css/main.css @@ -1,42 +1,15 @@ -*, *::before, *::after { +* { box-sizing: border-box; } -body { - font-family: Montserrat; - height: 100vh; - margin: 0; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -} - -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; +.full-screen { + /* positioning will be absolue */ + /* will take up whole screen */ + /* background will be ~0.5 opacity */ + /* grid-areas + "game-info *4" <-date, komi, handicap + "b-player-info*2 w-player-info*2" <- name, rank, rank-certainty + "record record record options" <- displays numbered record (stretch!), new game, get game record(stretch!) + pre-game record will display instructions + */ } \ No newline at end of file diff --git a/css/reset.css b/css/reset.css new file mode 100644 index 0000000..fa222c8 --- /dev/null +++ b/css/reset.css @@ -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; +} diff --git a/go wireframe.tif b/go wireframe.tif new file mode 100644 index 0000000..ee04bc7 Binary files /dev/null and b/go wireframe.tif differ diff --git a/index.html b/index.html index 78157d6..36f7570 100644 --- a/index.html +++ b/index.html @@ -1,74 +1,30 @@ - - - - Connect Four - - - + + + + + + + Go Cats -

CONNECT FOUR

-

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
+ + + +
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/js/main.js b/js/main.js index 8d4fefa..8794ef6 100644 --- a/js/main.js +++ b/js/main.js @@ -1,132 +1,83 @@ -/*----- constants -----*/ -const COLORS = { - '0': 'white', - '1': 'purple', - '-1': 'lime' -}; +// global constants declared -/*----- app's state (variables) -----*/ -let board, turn, winner; + // boardState, lastState, overlay (copy of boardState holding pre-move object, game end group state) + // bCaptures, wCaptures, gameInfo object, playerInfo object, turn, pass, gameRecord, + // handicapStones, deadShapes{} -/*----- cached element references -----*/ -const msgEl = document.getElementById('msg'); -/*----- event listeners -----*/ -document.querySelector('section.markers') - .addEventListener('click', handleClick); +// define initial game state -/*----- functions -----*/ -init(); + // define boardState and overlay as 2d 9x9 arrays + // 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() { - // Render the board - board.forEach(function(colArr, colIdx) { - // hide/show the column's marker depending if there are 0's or not - let marker = document.getElementById(`col${colIdx}`); - // ? : ; - // 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 = `${COLORS[winner].toUpperCase()} Wins!`; - } - } else { - msgEl.innerHTML = `${COLORS[turn].toUpperCase()}'s Turn`; - } -} +// cached elements + // store #menu for displaying game info + // store -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() { - // return the winner, 'T' or null - let winner = null; - // using a for loop because we want to stop looping if we find a winner - for (let colIdx = 0; colIdx < board.length; colIdx++) { - // check if any cells in the col lead to a winner - winner = checkCol(colIdx); - // done if winner is found, no reason to keep looking - if (winner) break; - } - return winner; -} +// set event listeners + // input listeners for player names, ranks, rank certainty (editable during game) + //input lister for handicap + komi (only editable pre-game) + // ::hover-over on board to preview move (with legal move logic) + // click on board to play move + // ::hover-over on either bowl for pass, one-level undo options (CSS implementation) + // click on menu items + // click on kifu to display game menu -function checkCol(colIdx) { - let winner = null; - for (let rowIdx = 0; rowIdx < board[colIdx].length; rowIdx++) { - // using the logical OR operator (||) prevents the checks to the right - // from ever running if a winner is found. For example, if checkUp returns - // a truthy value, checkRight and the checkDiag will never be called - winner = checkUp(colIdx, rowIdx) || checkRight(colIdx, rowIdx) || checkDiag(colIdx, rowIdx, 1) || checkDiag(colIdx, rowIdx, -1); - if (winner) break; - } - return winner; -} - -function checkUp(colIdx, rowIdx) { - // boundary check (can't check up if rowIdx is greater than 2) - if (rowIdx > 2) return null; - const colArr = board[colIdx]; - // ternary expression deluxe! - return ( Math.abs(colArr[rowIdx] + colArr[rowIdx + 1] + colArr[rowIdx + 2] + colArr[rowIdx + 3]) === 4 ) ? colArr[rowIdx] : null; -} - -function checkRight(colIdx, rowIdx) { - if (colIdx > 3) return null; - return ( Math.abs(board[colIdx][rowIdx] + board[colIdx + 1][rowIdx] + board[colIdx + 2][rowIdx] + board[colIdx + 3][rowIdx]) === 4 ) ? board[colIdx][rowIdx] : null; -} - -// Notice the extra vertOffset parameter for determining whether checking up or down vertically -function checkDiag(colIdx, rowIdx, vertOffset) { - // lot's of boundaries to check - if (colIdx > 3 || (vertOffset > 0 && rowIdx > 2) || (vertOffset < 0 && rowIdx < 3)) return null; - 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; -} \ No newline at end of file +// functions + // initialize game + // set handicap stones + // render + // render board + //render moves + //render preview + // render captures + // render player turn marker + // game-end + // render dead group suggestion + // render territory counts + // checkLegalMove + // clear overlay + // if move is not '0', move is illegal (opposing player or 'k' for ko) + // iterate through neighboring points in clockwise order + // if anyone is '0' move is legal - call render preview + // 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 + // if any neighboring point is '0' terminate cycle and move to next neighboring point of original move + // if there are unchecked points of 'hold' return + // 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 + // cycle through player group marking points as overlay: 'chk' || 'hold' + // if any neighboring point is '0' ternminate cycle and mark point as 'l' + // set move + // if checkLegalMove has returned '0' i2llegal move message? + // 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