Skip to content

Commit

Permalink
added solitaire test; fix rune logic, added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jaekwon committed Aug 17, 2021
1 parent 439d39f commit 68869de
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 15 deletions.
7 changes: 4 additions & 3 deletions op_eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ func (m *Machine) doOpEval() {
if err != nil {
panic("error in parsing character literal: " + err.Error())
}
if len(cstr) != 1 {
panic(fmt.Sprintf("error in parsing character literal: 1 character found, but got %v", len(cstr)))
runes := []rune(cstr)
if len(runes) != 1 {
panic(fmt.Sprintf("error in parsing character literal: 1 rune expected, but got %v (%s)", len(runes), cstr))
}
tv := TypedValue{T: UntypedRuneType}
tv.SetInt32(int32(rune(cstr[0])))
tv.SetInt32(int32(rune(runes[0])))
m.PushValue(tv)
case STRING:
m.PushValue(TypedValue{
Expand Down
9 changes: 6 additions & 3 deletions op_unary.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package gno

import "fmt"
import (
"fmt"
"math/big"
)

func (m *Machine) doOpUpos() {
ux := m.PopExpr().(*UnaryExpr)
Expand Down Expand Up @@ -42,11 +45,11 @@ func (m *Machine) doOpUneg() {
xv.SetUint64(-xv.GetUint64())
case UntypedBigintType, BigintType:
bv := xv.V.(BigintValue)
bv.V.Neg(bv.V)
xv.V = BigintValue{V: new(big.Int).Neg(bv.V)}
case nil:
// NOTE: for now only BigintValue is possible.
bv := xv.V.(BigintValue)
bv.V.Neg(bv.V)
xv.V = BigintValue{V: new(big.Int).Neg(bv.V)}
default:
panic(fmt.Sprintf("unexpected type %s in operation",
baseOf(xv.T)))
Expand Down
9 changes: 9 additions & 0 deletions tests/files/rune2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

func main() {
var runes = []rune(`....●●●...`)
println(runes)
}

// Output:
// slice[(46 int32),(46 int32),(46 int32),(46 int32),(9679 int32),(9679 int32),(9679 int32),(46 int32),(46 int32),(46 int32)]
10 changes: 10 additions & 0 deletions tests/files/unary.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

const N = 3

func main() {
println(N, -N)
}

// Output:
// 3 -3
9 changes: 9 additions & 0 deletions tests/files/unary1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

func main() {
var i int = 2
println(i, -i, +i)
}

// Output:
// 2 -2 2
117 changes: 117 additions & 0 deletions tests/files/zsolitaire.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// This program solves the (English) peg
// solitaire board game.
// http://en.wikipedia.org/wiki/Peg_solitaire

package main

import "fmt"

const N = 11 + 1 // length of a row (+1 for \n)

// The board must be surrounded by 2 illegal
// fields in each direction so that move()
// doesn't need to check the board boundaries.
// Periods represent illegal fields,
// ● are pegs, and ○ are holes.

var board = []rune(
`...........
...........
....●●●....
....●●●....
..●●●●●●●..
..●●●○●●●..
..●●●●●●●..
....●●●....
....●●●....
...........
...........
`)

// center is the position of the center hole if
// there is a single one; otherwise it is -1.
var center int

func init() {
n := 0
for pos, field := range board {
if field == '○' {
center = pos
n++
}
}
if n != 1 {
center = -1 // no single hole
}
}

var moves int // number of times move is called

// move tests if there is a peg at position pos that
// can jump over another peg in direction dir. If the
// move is valid, it is executed and move returns true.
// Otherwise, move returns false.
func move(pos, dir int) bool {
moves++
if board[pos] == '●' && board[pos+dir] == '●' && board[pos+2*dir] == '○' {
board[pos] = '○'
board[pos+dir] = '○'
board[pos+2*dir] = '●'
return true
}
return false
}

// unmove reverts a previously executed valid move.
func unmove(pos, dir int) {
board[pos] = '●'
board[pos+dir] = '●'
board[pos+2*dir] = '○'
}

// solve tries to find a sequence of moves such that
// there is only one peg left at the end; if center is
// >= 0, that last peg must be in the center position.
// If a solution is found, solve prints the board after
// each move in a backward fashion (i.e., the last
// board position is printed first, all the way back to
// the starting board position).
func solve() bool {
var last, n int
for pos, field := range board {
// try each board position
if field == '●' {
// found a peg
for _, dir := range [...]int{-1, -N, +1, +N} {
// try each direction
if move(pos, dir) {
// a valid move was found and executed,
// see if this new board has a solution
if solve() {
unmove(pos, dir)
fmt.Println(string(board))
return true
}
unmove(pos, dir)
}
}
last = pos
n++
}
}
// tried each possible move
if n == 1 && (center < 0 || last == center) {
// there's only one peg left
fmt.Println(string(board))
return true
}
// no solution found for this board
return false
}

func main() {
if !solve() {
fmt.Println("no solution found")
}
fmt.Println(moves, "moves tried")
}
2 changes: 2 additions & 0 deletions tests/imports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ func testImporter(out io.Writer) (imp gno.Importer) {
pkg.DefineGoNativeType(reflect.TypeOf((*fmt.Stringer)(nil)).Elem())
pkg.DefineGoNativeType(reflect.TypeOf((*fmt.Formatter)(nil)).Elem())
pkg.DefineGoNativeFunc("Println", func(a ...interface{}) (n int, err error) {
// NOTE: uncomment to debug long running tests
// fmt.Println(a...)
res := fmt.Sprintln(a...)
return out.Write([]byte(res))
})
Expand Down
6 changes: 6 additions & 0 deletions uverse.go
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,12 @@ func copyListToData(dst []byte, tvs []TypedValue) {
}
}

func copyListToRunes(dst []rune, tvs []TypedValue) {
for i := 0; i < len(tvs); i++ {
dst[i] = tvs[i].GetInt32()
}
}

func copyNativeToList(dst []TypedValue, rv reflect.Value, rvl int) {
// TODO: redundant go2GnoType() conversions.
for i := 0; i < rvl; i++ {
Expand Down
37 changes: 28 additions & 9 deletions values_conversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,13 @@ GNO_CASE:
tv.V = newSliceFromData([]byte(tv.GetString()))
tv.T = t // after tv.GetString()
case Int32Kind:
panic("not yet implemented")
runes := []TypedValue{}
str := tv.GetString()
for _, r := range str {
runes = append(runes, typedRune(r))
}
tv.V = newSliceFromList(runes)
tv.T = t // after tv.GetString()
default:
panic(fmt.Sprintf(
"cannot convert %s to %s",
Expand Down Expand Up @@ -638,7 +644,8 @@ GNO_CASE:
}
case SliceKind:
if t.Kind() == StringKind {
if tv.T.Elem().Kind() != Uint8Kind {
tk := tv.T.Elem().Kind()
if tk != Uint8Kind && tk != Int32Kind {
panic(fmt.Sprintf(
"cannot convert %s to %s",
tv.T.String(), t.String()))
Expand All @@ -648,13 +655,25 @@ GNO_CASE:
svo := sv.Offset
svl := sv.Length
if sv.Base.Data == nil {
data := make([]byte, svl)
copyListToData(
data[:svl],
sv.Base.List[svo:svo+svl])
strv := StringValue(string(data))
tv.T = t
tv.V = strv
if tk == Uint8Kind {
data := make([]byte, svl)
copyListToData(
data[:svl],
sv.Base.List[svo:svo+svl])
strv := StringValue(string(data))
tv.T = t
tv.V = strv
} else if tk == Int32Kind {
runes := make([]rune, svl)
copyListToRunes(
runes[:svl],
sv.Base.List[svo:svo+svl])
strv := StringValue(string(runes))
tv.T = t
tv.V = strv
} else {
panic("should not happen")
}
} else {
data := sv.Base.Data[svo : svo+svl]
strv := StringValue(string(data))
Expand Down

0 comments on commit 68869de

Please sign in to comment.