Morpion solitaire: Difference between revisions

Content added Content deleted
m (Fixed a spelling mistake/inconsistency)
Line 804: Line 804:
See:[[Morpion solitaire/Julia]]
See:[[Morpion solitaire/Julia]]


=={{header|Nim}}==
{{trans|Go}}
{{libheader|nim-ncurses}}

<lang Nim>import os, random, sequtils
import ncurses

const
LineLength = 5
Disjoint = 0

type
State {.pure.} = enum Blank, Occupied, DirNS, DirEW, DirNESW, DirNWSE, NewlyAdded, Current
States = set[State]
Board = seq[seq[States]]
Move = tuple[m, s, seqnum, x, y: int]

const Ofs = [(0, 1, DirNS), (1, 0, DirEW), (1, -1, DirNESW), (1, 1, DirNWSE)]


func set(board: var Board; value: State; x0, y0, x1, y1: int) =
for i in y0..y1:
for j in x0..x1:
board[i][j] = {value}


func initBoard(): Board =
let height, width = 3 * (LineLength - 1)
result = newSeqWith(height, newSeq[States](width))
result.set(Occupied, LineLength - 1, 1, 2 * LineLength - 3, height - 2)
result.set(Occupied, 1, LineLength - 1, width - 2, 2 * LineLength - 3)
result.set(Blank, LineLength, 2, 2 * LineLength - 4, height - 3)
result.set(Blank, 2, LineLength, width - 3, 2 * LineLength - 4)


func expand(board: var Board; dw, dh: int) =

# -1: expand low index end, +1: expand high index end.
let
height = board.len
width = board[0].len
nw = width + ord(dw != 0)
nh = height + ord(dh != 0)

var nboard = newSeqWith(nh, newSeq[States](nw))
let dw = -ord(dw < 0)
let dh = -ord(dh < 0)

for i in 0..<nh:
if i + dh notin 0..<height: continue
for j in 0..<nw:
if j + dw notin 0..<width: continue
nboard[i][j] = board[i + dh][j + dw]

board = move(nboard)


proc show(board: Board) =
for i, row in board:
for j, cell in row:
let str = if Current in cell: "X "
elif NewlyAdded in cell: "0 "
elif Occupied in cell: "+ "
else: " "
mvprintw(cint(i + 1), cint(j + 2), str)
refresh()


proc testPosition(board: Board; y, x: int; rec: var Move) =
let height = board.len
let width = board[0].len
if Occupied in board[y][x]: return

for m, (dx, dy, dir) in Ofs: # 4 directions.
for s in (1 - LineLength)..0: # offset line.
var k = -1
while k < LineLength:
inc k
if s + k == 0: continue
let xx = x + dx * (s + k)
let yy = y + dy * (s + k)
if xx < 0 or xx >= width or yy < 0 or yy >= height: break
if Occupied notin board[yy][xx]: break # No piece at position.
if dir in board[yy][xx]: break # This direction taken.
if k != LineLength: continue

# Position ok.
# Rand to even each option chance of being picked.
if rand(rec.seqnum) == 0:
rec.m = m; rec.s = s; rec.x = x; rec.y = y
inc rec.seqnum


proc addPiece(board: var Board; rec: Move) =
let (dx, dy, dir) = Ofs[rec.m]
board[rec.y][rec.x] = board[rec.y][rec.x] + {Current, Occupied}
for k in 0..<LineLength:
let xx = rec.x + dx * (k + rec.s)
let yy = rec.y + dy * (k + rec.s)
board[yy][xx].incl NewlyAdded
if k >= Disjoint or k < LineLength - Disjoint:
board[yy][xx].incl dir


proc nextMove(board: var Board): bool {.discardable.} =
var rec: Move
let maxi = board.high
let maxj = board[0].high

# Wipe last iteration new line markers.
for row in board.mitems:
for cell in row.mitems:
cell = cell - {NewlyAdded, Current}

# Randomly pick one of next legal move.
for i in 0..maxi:
for j in 0..maxj:
board.testPosition(i, j, rec)

# Didn't find any move, game over.
if rec.seqnum == 0: return false

board.addPiece(rec)

rec.x = if rec.x == maxj: 1
elif rec.x != 0: 0
else: -1
rec.y = if rec.y == maxi: 1
elif rec.y != 0: 0
else: -1

if rec.x != 0 or rec.y != 0: board.expand(rec.x, rec.y)
result = true


proc play() =
randomize()
var board = initBoard()
var waitKey = true
let win {.used.} = initscr()
noecho()
cbreak()

var move = 0
while true:
mvprintw(0, 0, "Move %d", move)
inc move
board.show()
if not board.nextMove():
board.nextMove()
board.show()
break
if not waitKey: sleep(100)
let ch = getch()
if ch == ord(' '):
waitKey = not waitKey
if waitKey: timeout(-1)
else: timeout(0)
elif ch == ord('q'):
break

timeout(-1)
getch()
nocbreak()
onecho()
endwin()

play()</lang>

{{out}}
Intermediate state:
<pre>Move 20

+
+++++
+ ++
+ ++ ++ +
+++++ +0+++
+ + 0 +
+ + X +
++++0+++++
+0 ++
++ +
+++++
+
</pre>


=={{header|Phix}}==
=={{header|Phix}}==