@slugbugblue/trax 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.yaml CHANGED
@@ -36,7 +36,7 @@ rules:
36
36
  - unix
37
37
  max-len:
38
38
  - warn
39
- - code: 119
39
+ - code: 99
40
40
  tabWidth: 2
41
41
  no-alert: error
42
42
  no-caller: error
package/engine.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /* Copyright 2021 Chad Transtrum
2
- *
2
+ *
3
3
  * Licensed under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License.
5
5
  * You may obtain a copy of the License at
6
- *
6
+ *
7
7
  * http://www.apache.org/licenses/LICENSE-2.0
8
- *
8
+ *
9
9
  * Unless required by applicable law or agreed to in writing, software
10
10
  * distributed under the License is distributed on an "AS IS" BASIS,
11
11
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,6 +19,7 @@
19
19
  // and then sorted alphabetically and given a single letter name, so 'bbww' becomes 'a'
20
20
  // which gives us six different tile names: a-f
21
21
 
22
+ const variants = ['trax', 'traxloop', 'trax8'] // known variants
22
23
 
23
24
  // fun trax helper constants
24
25
 
@@ -33,7 +34,9 @@ const symmetry = { // convert tile to different views
33
34
 
34
35
  const notation_regex = /^ *([@a-z]+) *(\d+) *([/\\+]) *$/i
35
36
 
36
- const variants = ['trax', 'traxloop', 'trax8'] // known variants
37
+ const color_of = { 1: 'w', 2: 'b' }
38
+ const player_num = { b: 2, w: 1 }
39
+ const other = { b: 'w', w: 'b' }
37
40
 
38
41
  // fun trax helper functions
39
42
 
@@ -128,6 +131,10 @@ const Trax = class {
128
131
  this.invalid = saved.invalid
129
132
  }
130
133
 
134
+ get color () { // get the color of the current player (w or b)
135
+ return color_of[this.turn]
136
+ }
137
+
131
138
  get game_over () { // returns true if the game is over
132
139
  return this.over
133
140
  }
@@ -194,7 +201,10 @@ const Trax = class {
194
201
  if (this.width > 7 && (x < this.left || x > this.right)) return false
195
202
  if (this.height > 7 && (y < this.top || y > this.bottom)) return false
196
203
  }
197
- return this.tile_at(x-1, y) || this.tile_at(x+1, y) || this.tile_at(x, y-1) || this.tile_at(x, y+1)
204
+ return Boolean(
205
+ this.tile_at(x-1, y) || this.tile_at(x+1, y) ||
206
+ this.tile_at(x, y-1) || this.tile_at(x, y+1)
207
+ )
198
208
  }
199
209
 
200
210
  possible_locations () {
@@ -293,7 +303,7 @@ const Trax = class {
293
303
 
294
304
  check_win (tiles) {
295
305
  let winner = false
296
- let colors = this.turn === 1 ? ['w', 'b'] : ['b', 'w'] // check win for current player first
306
+ let colors = [ this.color, other[this.color] ] // check win for current player first
297
307
  colors.forEach(color => {
298
308
  if (winner) return // skip the second player if the first has won
299
309
  tiles.forEach(tile => {
@@ -314,12 +324,14 @@ const Trax = class {
314
324
  })
315
325
  if (winner) {
316
326
  this.over = true
317
- this.turn = winner === 'w' ? 1 : 2
327
+ this.turn = player_num[winner]
318
328
  } else {
319
329
  // 8x8 Trax can end in a tie once there are no valid moves left
320
- if (this.rules === 'trax8' && this.possible_moves().length < 1) {
321
- this.over = true
322
- this.turn = 0 // tie
330
+ if (this.rules === 'trax8' && this.width > 7 && this.height > 7) {
331
+ if (this.possible_moves().length < 1) {
332
+ this.over = true
333
+ this.turn = 0 // tie
334
+ }
323
335
  }
324
336
  }
325
337
  }
@@ -371,12 +383,12 @@ const Trax = class {
371
383
  this.update_notation(notation)
372
384
  dropped.push(this.add_tile(type, x, y)) // play the tile
373
385
  dropped = dropped.concat(this.forced_moves(x, y)) // play all forced moves
374
- if (!tentative) this.check_win(dropped, tentative)
375
386
  if (this.invalid || tentative) {
376
387
  valid = false
377
388
  this.restore(saved) // abort! abort!
378
- } else if (!this.over) {
379
- this.turn = this.turn === 1 ? 2 : 1
389
+ } else {
390
+ this.check_win(dropped)
391
+ if (!this.over) this.turn = this.turn === 1 ? 2 : 1
380
392
  }
381
393
  }
382
394
  }
@@ -481,7 +493,7 @@ const Trax = class {
481
493
  })
482
494
  })
483
495
  })
484
- return norm
496
+ return (this.color || 't').toUpperCase() + norm
485
497
  }
486
498
 
487
499
  get normalized () {
@@ -490,7 +502,11 @@ const Trax = class {
490
502
  }
491
503
  }
492
504
 
493
- Trax.column = (col) => encode_col(col)
505
+ // add class methods
506
+ Trax.column = encode_col
494
507
  Trax.variants = variants
508
+ Trax.color_of = color_of
509
+ Trax.player_num = player_num
510
+ Trax.other = other
495
511
 
496
- module.exports = Trax
512
+ export default Trax
package/jsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "module": "commonjs",
3
+ "module": "es2020",
4
4
  "target": "es2020"
5
5
  },
6
6
  "checkJs": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slugbugblue/trax",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Trax game engine and friends",
5
5
  "keywords": [
6
6
  "trax",
@@ -11,10 +11,12 @@
11
11
  "bugs": "https://gitlab.com/slugbugblue/trax/issues",
12
12
  "license": "Apache-2.0",
13
13
  "author": "Chad Transtrum <chad@transtrum.net>",
14
- "main": "engine.js",
14
+ "exports": "./engine.js",
15
15
  "repository": "gitlab:slugbugblue/trax",
16
16
  "scripts": {
17
- "test": "tape tests.js"
17
+ "test": "tape tests.js",
18
+ "preversion": "npm test",
19
+ "postversion": "git push && git push --tags"
18
20
  },
19
21
  "devDependencies": {
20
22
  "eslint": "8.x",
@@ -22,7 +24,8 @@
22
24
  "typescript": "^4.5.4",
23
25
  "typescript-language-server": "^0.8.1"
24
26
  },
27
+ "type": "module",
25
28
  "engines": {
26
- "node": ">=16.0.0"
29
+ "node": "^14.14.0 || >=16.0.0"
27
30
  }
28
31
  }
package/tty.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /* Copyright 2021 Chad Transtrum
2
- *
2
+ *
3
3
  * Licensed under the Apache License, Version 2.0 (the "License");
4
4
  * you may not use this file except in compliance with the License.
5
5
  * You may obtain a copy of the License at
6
- *
6
+ *
7
7
  * http://www.apache.org/licenses/LICENSE-2.0
8
- *
8
+ *
9
9
  * Unless required by applicable law or agreed to in writing, software
10
10
  * distributed under the License is distributed on an "AS IS" BASIS,
11
11
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -13,17 +13,12 @@
13
13
  * limitations under the License.
14
14
  */
15
15
 
16
- // Console functions for Trax
16
+ // Ever wanted to draw Trax boards on the console? I have.
17
17
 
18
- /* eslint-disable no-console */
19
-
20
- const Trax = require('./engine')
21
-
22
- // fix Javascript's broken typeof
23
- const TypeOf = o => ({}).toString.call(o).slice(8,-1)
18
+ import Trax from './engine.js'
24
19
 
25
20
  const esc = '\x1b[' // start of console color escape code
26
- const off = esc + 'm'
21
+ const off = esc + 'm' // color reset code
27
22
 
28
23
  // display a message with optional color
29
24
  const out = (message, fgcolor, bgcolor) => {
@@ -34,34 +29,39 @@ const out = (message, fgcolor, bgcolor) => {
34
29
  console.log(ansi + message + off)
35
30
  }
36
31
 
32
+ let set = 'trax' // which color set should we draw with?
37
33
 
38
34
  // a little magic to display the game in progress
39
35
  const color_sets = { // Colors for terminal sequence: <Esc>[38;5;<color_num>m
36
+ // b, B, w, W: color of line for each player, capital for a winning line
37
+ // e: empty (ie, board) color, t: tile color
40
38
  trax: { b: 238, B: 57, e: 19, t: 74, w: 255, W: 184 },
41
39
  trax8: { b: 236, B: 21, e: 58, t: 137, w: 254, W: 117 },
42
40
  traxloop: { b: 235, B: 20, e: 17, t: 61, w: 253, W: 222 },
43
41
  }
44
42
 
43
+ const ln = 'm\u2584' // lower half block -- with the leading m to terminate ansi color escape
44
+ const up = 'm\u2588' // full block
45
+ const lt = 'm\u2599' // lower half and left half block
46
+ const rt = 'm\u259f' // lower half and right half block
47
+ const fg = n => '38;5;' + String(set[n]) // foreground color_num
48
+ const bg = n => '48;5;' + String(set[n]) // background color_num
49
+ const sp = () => esc + bg('e') + 'm ' // lower space
50
+ // tiles are displayed on two lines; the top half of the first line is empty
51
+ // and the second half is composed of three characters, up color surrounded by tile color
52
+ const uptty = clr => esc + fg('t') + ';' + bg('e') + ln
53
+ + esc + fg(clr) + ln + esc + fg('t') + ln + ' '
54
+ // the top half of the second line has both horizontal lines with a center transition
55
+ // while the bottom half is the tile background color surrounding the down color
56
+ const horiztty = clr => esc + fg('t') + ';' + bg(clr) + ln
57
+ const dntty = (clr, oppclr, char) => esc + fg(clr) + (char === up ? '' : ';' + bg(oppclr)) + char
58
+ // list of icon_char => tile line colors for easy reference in order up, right, down, left
59
+ const tiles = { a: 'bbww', b: 'bwbw', c: 'bwwb', d: 'wbbw', e: 'wbwb', f: 'wwbb' }
60
+
45
61
  // return the ANSI codes to display a 3x1.5 block tile, one line at a time
46
- const tile_tty = (set, tile, top) => { // top: true for first line, false for second
47
- const ln = 'm\u2584' // lower half block -- with the leading m to terminate a terminal color escape sequence
48
- const up = 'm\u2588' // full block
49
- const lt = 'm\u2599' // lower half and left half block
50
- const rt = 'm\u259f' // lower half and right half block
51
- const fg = n => '38;5;' + String(set[n]) // foreground color_num
52
- const bg = n => '48;5;' + String(set[n]) // background color_num
53
- const sp = esc + bg('e') + 'm ' // lower space
54
- // tiles are displayed on two lines; the top half of the first line is empty
55
- // and the second half is composed of three characters, up color surrounded by tile color
56
- const uptty = clr => esc + fg('t') + ';' + bg('e') + ln + esc + fg(clr) + ln + esc + fg('t') + ln + ' '
57
- // the top half of the second line has both horizontal lines with a center transition
58
- // while the bottom half is the tile background color surrounding the down color
59
- const horiztty = clr => esc + fg('t') + ';' + bg(clr) + ln
60
- const dntty = (clr, oppclr, char) => esc + fg(clr) + (char === up ? '' : ';' + bg(oppclr)) + char
61
- // list of icon_char => tile line colors for easy reference in order up, right, down, left
62
- const tiles = { a: 'bbww', b: 'bwbw', c: 'bwwb', d: 'wbbw', e: 'wbwb', f: 'wwbb' }
62
+ const tile_tty = (tile, top) => { // top: true for first line, false for second
63
63
  // quick access to tile color and its opposite in upper case
64
- const colors = { b: 'b', w: 'w', B: 'w', W: 'b' }
64
+ let colors = { b: 'b', w: 'w', B: 'w', W: 'b' }
65
65
  if (!(tile in tiles)) { // winning paths are represented by adding 6 to the tile char code
66
66
  tile = String.fromCharCode(tile.charCodeAt(0) - 6)
67
67
  if (tile in tiles) {
@@ -78,14 +78,14 @@ const tile_tty = (set, tile, top) => { // top: true for first line, false for se
78
78
  if (top) return uptty(colors[tile[0]])
79
79
  let center_char = tile[1] === tile[2] ? rt : tile[2] === tile[3] ? lt : up
80
80
  let centertty = dntty(colors[tile[2]], colors[tile[2].toUpperCase()], center_char)
81
- return horiztty(colors[tile[3]]) + centertty + horiztty(colors[tile[1]]) + sp
81
+ return horiztty(colors[tile[3]]) + centertty + horiztty(colors[tile[1]]) + sp()
82
82
  }
83
83
  if (top) return '??? '
84
84
  return '\'\'\' '
85
85
  }
86
86
 
87
87
  const print_icon = (icon, set_name) => {
88
- let set = color_sets[set_name] || color_sets.trax
88
+ set = color_sets[set_name] || color_sets.trax
89
89
  const on = esc + '38;5;' + String(set.t) + ';48;5;' + String(set.e) + 'm'
90
90
  let o1 = ' '
91
91
  let o2 = '1 '
@@ -110,8 +110,8 @@ const print_icon = (icon, set_name) => {
110
110
  o2 += ' '.repeat(empty * 4)
111
111
  line_width += empty
112
112
  } else {
113
- o1 += tile_tty(set, c, 'top')
114
- o2 += tile_tty(set, c)
113
+ o1 += tile_tty(c, 'top')
114
+ o2 += tile_tty(c)
115
115
  line_width++
116
116
  }
117
117
  }
@@ -144,7 +144,7 @@ const trax_game = (game='trax', moves) => {
144
144
  if (game instanceof Trax) {
145
145
  trax = game
146
146
  if (moves) {
147
- if (TypeOf(moves) === 'String') moves = moves.split(' ')
147
+ if (typeof moves === 'string') moves = moves.split(' ')
148
148
  moves.forEach(move => trax.drop_tile(move))
149
149
  }
150
150
  } else {
@@ -169,7 +169,7 @@ const display_game = (game='trax', moves='') => {
169
169
  }
170
170
  }
171
171
 
172
- module.exports = {
172
+ export default {
173
173
  display: display_game,
174
174
  game: trax_game,
175
175
  out,